diff --git a/Cargo.lock b/Cargo.lock index 5a3906c470f77..45cace567ce49 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3889,6 +3889,7 @@ dependencies = [ name = "rustc_hir" version = "0.0.0" dependencies = [ + "bitflags", "odht", "rustc_abi", "rustc_arena", diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 9bfcd232221ba..067f862f4d187 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -40,7 +40,7 @@ use std::iter; use ast::visit::Visitor; use hir::def::{DefKind, PartialRes, Res}; -use hir::{BodyId, HirId}; +use hir::{BodyId, HirId, PathFlags}; use rustc_abi::ExternAbi; use rustc_ast::*; use rustc_errors::ErrorGuaranteed; @@ -264,7 +264,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir_id: self.next_id(), res: Res::Local(param_id), args: None, - infer_args: false, + flags: PathFlags::empty(), })); let path = self.arena.alloc(hir::Path { span, res: Res::Local(param_id), segments }); @@ -366,6 +366,7 @@ impl<'hir> LoweringContext<'_, 'hir> { GenericArgsMode::Err, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, + PathFlags::empty(), ); let segment = self.arena.alloc(segment); diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 1245d48975470..f03584ccb7539 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -5,10 +5,9 @@ use rustc_ast::ptr::P as AstP; use rustc_ast::*; use rustc_ast_pretty::pprust::expr_to_string; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_hir as hir; use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{HirId, find_attr}; +use rustc_hir::{self as hir, HirId, PathFlags, find_attr}; use rustc_middle::span_bug; use rustc_middle::ty::TyCtxt; use rustc_session::errors::report_lit_error; @@ -126,6 +125,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ImplTraitContext::Disallowed(ImplTraitPosition::Path), // Method calls can't have bound modifiers None, + PathFlags::empty(), )); let receiver = self.lower_expr(receiver); let args = diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index d097e3cbaa822..cc7917c5493ea 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -54,7 +54,7 @@ use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId}; use rustc_hir::lints::DelayedLint; use rustc_hir::{ self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LifetimeSource, - LifetimeSyntax, ParamName, TraitCandidate, + LifetimeSyntax, ParamName, PathFlags, TraitCandidate, }; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_macros::extension; @@ -781,6 +781,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let def_id = self.tcx.require_lang_item(lang_item, span); let def_kind = self.tcx.def_kind(def_id); let res = Res::Def(def_kind, def_id); + let mut flags = PathFlags::empty(); + flags.set(PathFlags::INFER_ARGS, args.is_none()); self.arena.alloc(hir::Path { span, res, @@ -789,7 +791,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir_id: self.next_id(), res, args, - infer_args: args.is_none(), + flags, }]), }) } diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index c80ef275c801a..081cad73e352a 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use rustc_ast::{self as ast, *}; use rustc_hir::def::{DefKind, PartialRes, PerNS, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::{self as hir, GenericArg}; +use rustc_hir::{self as hir, GenericArg, PathFlags}; use rustc_middle::{span_bug, ty}; use rustc_session::parse::add_feature_diagnostics; use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym}; @@ -135,6 +135,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { generic_args_mode, itctx(i), bound_modifier_allowed_features.clone(), + PathFlags::empty(), ) }, )), @@ -160,16 +161,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } // Create the innermost type that we're projecting from. - let mut ty = if path.segments.is_empty() { + let (mut ty, flags) = if path.segments.is_empty() { // If the base path is empty that means there exists a // syntactical `Self`, e.g., `&i32` in `<&i32>::clone`. - qself.expect("missing QSelf for ::...") + (qself.expect("missing QSelf for ::..."), PathFlags::empty()) } else { // Otherwise, the base path is an implicit `Self` type path, // e.g., `Vec` in `Vec::new` or `::Item` in // `::Item::default`. let new_id = self.next_id(); - self.arena.alloc(self.ty_path(new_id, path.span, hir::QPath::Resolved(qself, path))) + ( + &*self.arena.alloc(self.ty_path( + new_id, + path.span, + hir::QPath::Resolved(qself, path), + )), + PathFlags::IMPLICIT_SELF, + ) }; // Anything after the base path are associated "extensions", @@ -199,6 +207,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { generic_args_mode, itctx(i), None, + flags, )); let qpath = hir::QPath::TypeRelative(ty, hir_segment); @@ -241,6 +250,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { GenericArgsMode::Err, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, + PathFlags::empty(), ) })), span: self.lower_span(p.span), @@ -258,6 +268,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // This is passed down to the implicit associated type binding in // parenthesized bounds. bound_modifier_allowed_features: Option>, + mut flags: PathFlags, ) -> hir::PathSegment<'hir> { debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment); let (mut generic_args, infer_args) = if let Some(generic_args) = segment.args.as_deref() { @@ -400,11 +411,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { segment.ident, segment.id, hir_id, ); + flags.set(PathFlags::INFER_ARGS, infer_args); + hir::PathSegment { ident: self.lower_ident(segment.ident), hir_id, res: self.lower_res(res), - infer_args, + flags, args: if generic_args.is_empty() && generic_args.span.is_empty() { None } else { diff --git a/compiler/rustc_baked_icu_data/src/lib.rs b/compiler/rustc_baked_icu_data/src/lib.rs index f3f6522f57587..05ad644af1a26 100644 --- a/compiler/rustc_baked_icu_data/src/lib.rs +++ b/compiler/rustc_baked_icu_data/src/lib.rs @@ -21,13 +21,14 @@ //! ``` // tidy-alphabetical-start -#![allow(elided_lifetimes_in_paths)] #![allow(internal_features)] #![allow(unreachable_pub)] // because this crate is mostly generated code #![doc(rust_logo)] #![feature(rustdoc_internals)] // #![warn(unreachable_pub)] // don't use because this crate is mostly generated code // tidy-alphabetical-end +#![cfg_attr(bootstrap, allow(elided_lifetimes_in_paths))] +#![cfg_attr(not(bootstrap), allow(hidden_lifetimes_in_paths))] mod data { include!("data/mod.rs"); diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml index 539d2e6f0b179..a3cb609105ccb 100644 --- a/compiler/rustc_hir/Cargo.toml +++ b/compiler/rustc_hir/Cargo.toml @@ -5,6 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start +bitflags = "2.4.1" odht = { version = "0.3.1", features = ["nightly"] } rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index c30c830f9af84..ec3f9dbaa3f2b 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -16,6 +16,7 @@ pub use rustc_ast::{ }; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::sorted_map::SortedMap; +use rustc_data_structures::stable_hasher::HashStable; use rustc_data_structures::tagged_ptr::TaggedRef; use rustc_index::IndexVec; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; @@ -374,17 +375,37 @@ pub struct PathSegment<'hir> { /// distinction. pub args: Option<&'hir GenericArgs<'hir>>, - /// Whether to infer remaining type parameters, if any. - /// This only applies to expression and pattern paths, and - /// out of those only the segments with no type parameters - /// to begin with, e.g., `Vec::new` is `>::new::<..>`. - pub infer_args: bool, + pub flags: PathFlags, +} + +bitflags::bitflags! { + #[derive(Debug, Clone, Copy)] + pub struct PathFlags: u8 { + /// Whether to infer remaining type parameters, if any. + /// This only applies to expression and pattern paths, and + /// out of those only the segments with no type parameters + /// to begin with, e.g., `Vec::new` is `>::new::<..>`. + const INFER_ARGS = 1 << 0; + + /// Whether this path is an implicit `Self` type path. + const IMPLICIT_SELF = 1 << 1; + } +} + +impl HashStable for PathFlags { + fn hash_stable( + &self, + hcx: &mut CTX, + hasher: &mut rustc_data_structures::stable_hasher::StableHasher, + ) { + self.bits().hash_stable(hcx, hasher) + } } impl<'hir> PathSegment<'hir> { /// Converts an identifier to the corresponding segment. pub fn new(ident: Ident, hir_id: HirId, res: Res) -> PathSegment<'hir> { - PathSegment { ident, hir_id, res, infer_args: true, args: None } + PathSegment { ident, hir_id, res, flags: PathFlags::INFER_ARGS, args: None } } pub fn invalid() -> Self { @@ -399,6 +420,14 @@ impl<'hir> PathSegment<'hir> { DUMMY } } + + pub fn infer_args(&self) -> bool { + self.flags.contains(PathFlags::INFER_ARGS) + } + + pub fn implicit_self(&self) -> bool { + self.flags.contains(PathFlags::IMPLICIT_SELF) + } } /// A constant that enters the type system, used for arguments to const generics (e.g. array lengths). diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 23fa466859a05..e65900d0ba8cc 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1427,7 +1427,7 @@ pub fn walk_path_segment<'v, V: Visitor<'v>>( visitor: &mut V, segment: &'v PathSegment<'v>, ) -> V::Result { - let PathSegment { ident, hir_id, res: _, args, infer_args: _ } = segment; + let PathSegment { ident, hir_id, res: _, args, flags: _ } = segment; try_visit!(visitor.visit_ident(*ident)); try_visit!(visitor.visit_id(*hir_id)); visit_opt!(visitor, visit_generic_args, *args); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 386e1091ac4eb..edd1b8079b198 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -6,7 +6,7 @@ use rustc_errors::struct_span_code_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; -use rustc_hir::{AmbigArg, PolyTraitRef}; +use rustc_hir::{AmbigArg, PathFlags, PolyTraitRef}; use rustc_middle::bug; use rustc_middle::ty::{ self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, @@ -602,7 +602,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir_id: constraint.hir_id, res: Res::Err, args: Some(constraint.gen_args), - infer_args: false, + flags: PathFlags::empty(), }; let alias_args = self.lower_generic_args_of_assoc_item( diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs index fc519c194bb9d..7f13bedca5d69 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -427,8 +427,8 @@ pub(crate) fn check_generic_arg_count( }) .count(); let named_const_param_count = param_counts.consts - synth_const_param_count; - let infer_lifetimes = - (gen_pos != GenericArgPosition::Type || seg.infer_args) && !gen_args.has_lifetime_params(); + let infer_lifetimes = (gen_pos != GenericArgPosition::Type || seg.infer_args()) + && !gen_args.has_lifetime_params(); if gen_pos != GenericArgPosition::Type && let Some(c) = gen_args.constraints.first() @@ -577,7 +577,7 @@ pub(crate) fn check_generic_arg_count( }; let args_correct = { - let expected_min = if seg.infer_args { + let expected_min = if seg.infer_args() { 0 } else { param_counts.consts + named_type_param_count diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 7e2bfa9f920c7..3584907c9a13d 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -670,7 +670,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { def_id, span, generic_args: segment.args(), - infer_args: segment.infer_args, + infer_args: segment.infer_args(), incorrect_args: &arg_count.correct, }; let args = lower_generic_args( diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 0b3d50ff2199f..930a2526312f2 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1238,10 +1238,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !self.infer_args_for_err.contains(&index) { // Check whether the user has provided generic arguments. if let Some(data) = self.segments[index].args { - return (Some(data), self.segments[index].infer_args); + return (Some(data), self.segments[index].infer_args()); } } - return (None, self.segments[index].infer_args); + return (None, self.segments[index].infer_args()); } (None, true) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 4d0c0c94a8138..984a3aa80e467 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -292,7 +292,11 @@ lint_hidden_glob_reexport = private item shadows public glob re-export .note_glob_reexport = the name `{$name}` in the {$namespace} namespace is supposed to be publicly re-exported here .note_private_item = but the private item here shadows it -lint_hidden_lifetime_parameters = hidden lifetime parameters in types are deprecated +lint_hidden_lifetime_in_path = + paths containing hidden lifetime parameters are deprecated + +lint_hidden_lifetime_in_path_suggestion = + indicate the anonymous lifetime lint_hidden_unicode_codepoints = unicode codepoint changing visible direction of text present in {$label} .label = this {$label} contains {$count -> diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 11181d10af5ee..7c68553f2f9ee 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -288,6 +288,26 @@ impl LintStore { self.by_name.insert(old_name.to_string(), Renamed(new_name.to_string(), target)); } + #[track_caller] + pub fn register_renamed_group(&mut self, old_name: &'static str, new_name: &'static str) { + let prev_lint = self.lint_groups.insert( + old_name, + LintGroup { + lint_ids: vec![], + is_externally_loaded: false, + depr: Some(LintAlias { name: new_name, silent: false }), + }, + ); + + if prev_lint.is_some() { + bug!("The lint group {old_name} has already been registered"); + } + + if !self.lint_groups.contains_key(new_name) { + bug!("The lint group {new_name} has not been registered"); + } + } + pub fn register_removed(&mut self, name: &str, reason: &str) { self.by_name.insert(name.into(), Removed(reason.into())); } diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index f0fbf5bc81e9b..9ac5321ade478 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -1,9 +1,7 @@ use std::borrow::Cow; use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS; -use rustc_errors::{ - Applicability, Diag, DiagArgValue, LintDiagnostic, elided_lifetime_in_path_suggestion, -}; +use rustc_errors::{Applicability, Diag, DiagArgValue, LintDiagnostic}; use rustc_middle::middle::stability; use rustc_middle::ty::TyCtxt; use rustc_session::Session; @@ -72,19 +70,6 @@ pub fn decorate_builtin_lint( lints::MacroExpandedMacroExportsAccessedByAbsolutePaths { definition: span_def } .decorate_lint(diag) } - - BuiltinLintDiag::ElidedLifetimesInPaths(n, path_span, incl_angl_brckt, insertion_span) => { - lints::ElidedLifetimesInPaths { - subdiag: elided_lifetime_in_path_suggestion( - sess.source_map(), - n, - path_span, - incl_angl_brckt, - insertion_span, - ), - } - .decorate_lint(diag); - } BuiltinLintDiag::UnknownCrateTypes { span, candidate } => { let sugg = candidate.map(|candidate| lints::UnknownCrateTypesSub { span, candidate }); lints::UnknownCrateTypes { sugg }.decorate_lint(diag); diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index f06757b3c2379..e7e63be80beff 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -248,6 +248,7 @@ late_lint_methods!( UnqualifiedLocalImports: UnqualifiedLocalImports, CheckTransmutes: CheckTransmutes, LifetimeSyntax: LifetimeSyntax, + HiddenLifetimesInTypePaths: HiddenLifetimesInTypePaths::default(), ] ] ); @@ -268,7 +269,7 @@ pub fn new_lint_store(internal_lints: bool) -> LintStore { /// `rustc_session::lint::builtin`). fn register_builtins(store: &mut LintStore) { macro_rules! add_lint_group { - ($name:expr, $($lint:ident),*) => ( + ($name:expr, $($lint:ident),* $(,)?) => ( store.register_group(false, $name, None, vec![$(LintId::of($lint)),*]); ) } @@ -283,7 +284,7 @@ fn register_builtins(store: &mut LintStore) { "nonstandard_style", NON_CAMEL_CASE_TYPES, NON_SNAKE_CASE, - NON_UPPER_CASE_GLOBALS + NON_UPPER_CASE_GLOBALS, ); add_lint_group!( @@ -309,7 +310,7 @@ fn register_builtins(store: &mut LintStore) { UNUSED_PARENS, UNUSED_BRACES, REDUNDANT_SEMICOLONS, - MAP_UNIT_FN + MAP_UNIT_FN, ); add_lint_group!("let_underscore", LET_UNDERSCORE_DROP, LET_UNDERSCORE_LOCK); @@ -319,14 +320,16 @@ fn register_builtins(store: &mut LintStore) { BARE_TRAIT_OBJECTS, UNUSED_EXTERN_CRATES, ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, - ELIDED_LIFETIMES_IN_PATHS, - EXPLICIT_OUTLIVES_REQUIREMENTS // FIXME(#52665, #47816) not always applicable and not all - // macros are ready for this yet. - // UNREACHABLE_PUB, - - // FIXME macro crates are not up for this yet, too much - // breakage is seen if we try to encourage this lint. - // MACRO_USE_EXTERN_CRATE + HIDDEN_LIFETIMES_IN_OUTPUT_PATHS, + HIDDEN_LIFETIMES_IN_INPUT_PATHS, + HIDDEN_LIFETIMES_IN_TYPE_PATHS, + EXPLICIT_OUTLIVES_REQUIREMENTS, + // FIXME(#52665, #47816) not always applicable and not all + // macros are ready for this yet. + // UNREACHABLE_PUB, + // FIXME macro crates are not up for this yet, too much + // breakage is seen if we try to encourage this lint. + // MACRO_USE_EXTERN_CRATE ); add_lint_group!("keyword_idents", KEYWORD_IDENTS_2018, KEYWORD_IDENTS_2024); @@ -347,9 +350,15 @@ fn register_builtins(store: &mut LintStore) { UNKNOWN_DIAGNOSTIC_ATTRIBUTES ); + add_lint_group!( + "hidden_lifetimes_in_paths", + HIDDEN_LIFETIMES_IN_OUTPUT_PATHS, + HIDDEN_LIFETIMES_IN_INPUT_PATHS, + HIDDEN_LIFETIMES_IN_TYPE_PATHS, + ); + // Register renamed and removed lints. store.register_renamed("single_use_lifetime", "single_use_lifetimes"); - store.register_renamed("elided_lifetime_in_path", "elided_lifetimes_in_paths"); store.register_renamed("bare_trait_object", "bare_trait_objects"); store.register_renamed("unstable_name_collision", "unstable_name_collisions"); store.register_renamed("unused_doc_comment", "unused_doc_comments"); @@ -365,6 +374,10 @@ fn register_builtins(store: &mut LintStore) { store.register_renamed("temporary_cstring_as_ptr", "dangling_pointers_from_temporaries"); store.register_renamed("elided_named_lifetimes", "mismatched_lifetime_syntaxes"); + // Register renamed lint groups + store.register_renamed_group("elided_lifetime_in_path", "hidden_lifetimes_in_paths"); + store.register_renamed_group("elided_lifetimes_in_paths", "hidden_lifetimes_in_paths"); + // These were moved to tool lints, but rustc still sees them when compiling normally, before // tool lints are registered, so `check_tool_name_for_backwards_compat` doesn't work. Use // `register_removed` explicitly. diff --git a/compiler/rustc_lint/src/lifetime_syntax.rs b/compiler/rustc_lint/src/lifetime_syntax.rs index 2a5a34cdc6e94..c46f2acd2d519 100644 --- a/compiler/rustc_lint/src/lifetime_syntax.rs +++ b/compiler/rustc_lint/src/lifetime_syntax.rs @@ -1,7 +1,10 @@ +use std::slice; + use rustc_data_structures::fx::FxIndexMap; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{self as hir, LifetimeSource}; -use rustc_session::{declare_lint, declare_lint_pass}; +use rustc_session::lint::Lint; +use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass}; use rustc_span::Span; use tracing::instrument; @@ -71,7 +74,82 @@ declare_lint! { "detects when a lifetime uses different syntax between arguments and return values" } -declare_lint_pass!(LifetimeSyntax => [MISMATCHED_LIFETIME_SYNTAXES]); +declare_lint! { + /// The `hidden_lifetimes_in_input_paths` lint detects the use of + /// hidden lifetime parameters in types occurring as a function + /// argument. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// struct ContainsLifetime<'a>(&'a i32); + /// + /// #[deny(hidden_lifetimes_in_input_paths)] + /// fn foo(x: ContainsLifetime) {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Hidden lifetime parameters can make it difficult to see at a + /// glance that borrowing is occurring. + /// + /// This lint ensures that lifetime parameters are always + /// explicitly stated, even if it is the `'_` [placeholder + /// lifetime]. + /// + /// This lint is "allow" by default as function arguments by + /// themselves do not usually cause much confusion. + /// + /// [placeholder lifetime]: https://doc.rust-lang.org/reference/lifetime-elision.html#lifetime-elision-in-functions + pub HIDDEN_LIFETIMES_IN_INPUT_PATHS, + Allow, + "hidden lifetime parameters in types in function arguments may be confusing" +} + +declare_lint! { + /// The `hidden_lifetimes_in_output_paths` lint detects the use + /// of hidden lifetime parameters in types occurring as a function + /// return value. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// struct ContainsLifetime<'a>(&'a i32); + /// + /// #[deny(hidden_lifetimes_in_output_paths)] + /// fn foo(x: &i32) -> ContainsLifetime { + /// ContainsLifetime(x) + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Hidden lifetime parameters can make it difficult to see at a + /// glance that borrowing is occurring. This is especially true + /// when a type is used as a function's return value: lifetime + /// elision will link the return value's lifetime to an argument's + /// lifetime, but no syntax in the function signature indicates + /// that. + /// + /// This lint ensures that lifetime parameters are always + /// explicitly stated, even if it is the `'_` [placeholder + /// lifetime]. + /// + /// [placeholder lifetime]: https://doc.rust-lang.org/reference/lifetime-elision.html#lifetime-elision-in-functions + pub HIDDEN_LIFETIMES_IN_OUTPUT_PATHS, + Allow, + "hidden lifetime parameters in types in function return values are deprecated" +} + +declare_lint_pass!(LifetimeSyntax => [ + MISMATCHED_LIFETIME_SYNTAXES, + HIDDEN_LIFETIMES_IN_INPUT_PATHS, + HIDDEN_LIFETIMES_IN_OUTPUT_PATHS, +]); impl<'tcx> LateLintPass<'tcx> for LifetimeSyntax { #[instrument(skip_all)] @@ -123,6 +201,8 @@ fn check_fn_like<'tcx>(cx: &LateContext<'tcx>, fd: &'tcx hir::FnDecl<'tcx>) { } report_mismatches(cx, &input_map, &output_map); + report_hidden_in_paths(cx, &input_map, HIDDEN_LIFETIMES_IN_INPUT_PATHS); + report_hidden_in_paths(cx, &output_map, HIDDEN_LIFETIMES_IN_OUTPUT_PATHS); } #[instrument(skip_all)] @@ -512,6 +592,50 @@ fn build_mismatch_suggestion( } } +fn report_hidden_in_paths<'tcx>( + cx: &LateContext<'tcx>, + info_map: &LifetimeInfoMap<'tcx>, + lint: &'static Lint, +) { + let relevant_lifetimes = info_map + .iter() + .filter(|&(&&res, _)| reportable_lifetime_resolution(res)) + .flat_map(|(_, info)| info) + .filter(|info| { + matches!(info.lifetime.source, LifetimeSource::Path { .. }) + && info.lifetime.is_implicit() + }); + + let mut reporting_spans = Vec::new(); + let mut suggestions = Vec::new(); + + for info in relevant_lifetimes { + reporting_spans.push(info.reporting_span()); + suggestions.push(info.suggestion("'_")); + } + + if reporting_spans.is_empty() { + return; + } + + cx.emit_span_lint( + lint, + reporting_spans, + lints::HiddenLifetimeInPath { + suggestions: lints::HiddenLifetimeInPathSuggestion { suggestions }, + }, + ); +} + +/// We don't care about errors, nor do we care about the lifetime +/// inside of a trait object. +fn reportable_lifetime_resolution(kind: hir::LifetimeKind) -> bool { + matches!( + kind, + hir::LifetimeKind::Param(..) | hir::LifetimeKind::Infer | hir::LifetimeKind::Static + ) +} + #[derive(Debug)] struct Info<'tcx> { type_span: Span, @@ -614,3 +738,148 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeInfoCollector<'a, 'tcx> { self.referenced_type_span = old_referenced_type_span; } } + +declare_lint! { + /// The `hidden_lifetimes_in_type_paths` lint detects the use of + /// hidden lifetime parameters in types not part of a function's + /// arguments or return values. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// struct ContainsLifetime<'a>(&'a i32); + /// + /// #[deny(hidden_lifetimes_in_type_paths)] + /// static FOO: ContainsLifetime = ContainsLifetime(&42); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Hidden lifetime parameters can make it difficult to see at a + /// glance that borrowing is occurring. + /// + /// This lint ensures that lifetime parameters are always + /// explicitly stated, even if it is the `'_` [placeholder + /// lifetime]. + /// + /// [placeholder lifetime]: https://doc.rust-lang.org/reference/lifetime-elision.html#lifetime-elision-in-functions + pub HIDDEN_LIFETIMES_IN_TYPE_PATHS, + Allow, + "hidden lifetime parameters in types outside function signatures are discouraged" +} + +#[derive(Default)] +pub(crate) struct HiddenLifetimesInTypePaths { + inside_fn_signature: bool, +} + +impl_lint_pass!(HiddenLifetimesInTypePaths => [HIDDEN_LIFETIMES_IN_TYPE_PATHS]); + +// Do not lint about usages such as `ContainsLifetime::method` or +// `ContainsLifetimeAndType::::method`. +fn parent_path_implicit_self<'tcx>(cx: &LateContext<'tcx>, parent_hir_id: hir::HirId) -> bool { + let parent_hir_node = cx.tcx.parent_hir_node(parent_hir_id); + tracing::debug!(?parent_hir_node, "parent_hir_node"); + + fn path_is_implicit_self(path: hir::QPath<'_>) -> bool { + match path { + hir::QPath::TypeRelative(_, seg) => seg.implicit_self(), + _ => false, + } + } + + if let hir::Node::Expr(expr) = parent_hir_node { + return match expr.kind { + hir::ExprKind::Path(path) => path_is_implicit_self(path), + hir::ExprKind::Struct(path, _, _) => path_is_implicit_self(*path), + _ => false, + }; + } + + if let hir::Node::Pat(pat) = parent_hir_node + && let hir::PatKind::Struct(path, _, _) | hir::PatKind::TupleStruct(path, _, _) = pat.kind + { + return path_is_implicit_self(path); + } + + if let hir::Node::PatExpr(expr) = parent_hir_node + && let hir::PatExprKind::Path(path) = expr.kind + { + return path_is_implicit_self(path); + } + + false +} + +impl<'tcx> LateLintPass<'tcx> for HiddenLifetimesInTypePaths { + #[instrument(skip(self, cx))] + fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'tcx, hir::AmbigArg>) { + if self.inside_fn_signature { + return; + } + + if parent_path_implicit_self(cx, ty.hir_id) { + return; + } + + let hir::TyKind::Path(path) = ty.kind else { return }; + + let path_segments = match path { + hir::QPath::Resolved(_ty, path) => path.segments, + + hir::QPath::TypeRelative(_ty, path_segment) => slice::from_ref(path_segment), + + hir::QPath::LangItem(..) => &[], + }; + + let mut suggestions = Vec::new(); + + for path_segment in path_segments { + for arg in path_segment.args().args { + if let hir::GenericArg::Lifetime(lifetime) = arg + && lifetime.is_implicit() + && reportable_lifetime_resolution(lifetime.kind) + { + suggestions.push(lifetime.suggestion("'_")) + } + } + } + + if suggestions.is_empty() { + return; + } + + cx.emit_span_lint( + HIDDEN_LIFETIMES_IN_TYPE_PATHS, + ty.span, + lints::HiddenLifetimeInPath { + suggestions: lints::HiddenLifetimeInPathSuggestion { suggestions }, + }, + ); + } + + #[instrument(skip_all)] + fn check_fn( + &mut self, + _: &LateContext<'tcx>, + _: hir::intravisit::FnKind<'tcx>, + _: &'tcx hir::FnDecl<'tcx>, + _: &'tcx hir::Body<'tcx>, + _: rustc_span::Span, + _: rustc_span::def_id::LocalDefId, + ) { + // We make the assumption that we will visit the function + // declaration first, before visiting the body. + self.inside_fn_signature = true; + } + + // This may be a function's body, which would indicate that we are + // no longer in the signature. Even if it's not, a body cannot + // occur inside a function signature. + #[instrument(skip_all)] + fn check_body(&mut self, _: &LateContext<'tcx>, _: &hir::Body<'tcx>) { + self.inside_fn_signature = false; + } +} diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index ef63c0dee8c2e..1b4a657e371f0 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -4,8 +4,8 @@ use std::num::NonZero; use rustc_abi::ExternAbi; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString, ElidedLifetimeInPathSubdiag, - EmissionGuarantee, LintDiagnostic, MultiSpan, Subdiagnostic, SuggestionStyle, + Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString, EmissionGuarantee, + LintDiagnostic, MultiSpan, Subdiagnostic, SuggestionStyle, }; use rustc_hir as hir; use rustc_hir::def::Namespace; @@ -2778,13 +2778,6 @@ pub(crate) struct MacroExpandedMacroExportsAccessedByAbsolutePaths { pub definition: Span, } -#[derive(LintDiagnostic)] -#[diag(lint_hidden_lifetime_parameters)] -pub(crate) struct ElidedLifetimesInPaths { - #[subdiagnostic] - pub subdiag: ElidedLifetimeInPathSubdiag, -} - #[derive(LintDiagnostic)] #[diag(lint_invalid_crate_type_value)] pub(crate) struct UnknownCrateTypes { @@ -3389,3 +3382,24 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion { } } } + +#[derive(LintDiagnostic)] +#[diag(lint_hidden_lifetime_in_path)] +pub(crate) struct HiddenLifetimeInPath { + #[subdiagnostic] + pub suggestions: HiddenLifetimeInPathSuggestion, +} + +pub(crate) struct HiddenLifetimeInPathSuggestion { + pub suggestions: Vec<(Span, String)>, +} + +impl Subdiagnostic for HiddenLifetimeInPathSuggestion { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { + diag.multipart_suggestion_verbose( + fluent::lint_hidden_lifetime_in_path_suggestion, + self.suggestions, + Applicability::MachineApplicable, + ); + } +} diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 3b84c6b611016..832596112882e 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -39,7 +39,6 @@ declare_lint_pass! { DEPRECATED_WHERE_CLAUSE_LOCATION, DUPLICATE_MACRO_ATTRIBUTES, ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT, - ELIDED_LIFETIMES_IN_PATHS, EXPLICIT_BUILTIN_CFGS_IN_FLAGS, EXPORTED_PRIVATE_DEPENDENCIES, FFI_UNWIND_CALLS, @@ -1752,41 +1751,6 @@ declare_lint! { }; } -declare_lint! { - /// The `elided_lifetimes_in_paths` lint detects the use of hidden - /// lifetime parameters. - /// - /// ### Example - /// - /// ```rust,compile_fail - /// #![deny(elided_lifetimes_in_paths)] - /// #![deny(warnings)] - /// struct Foo<'a> { - /// x: &'a u32 - /// } - /// - /// fn foo(x: &Foo) { - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// Elided lifetime parameters can make it difficult to see at a glance - /// that borrowing is occurring. This lint ensures that lifetime - /// parameters are always explicitly stated, even if it is the `'_` - /// [placeholder lifetime]. - /// - /// This lint is "allow" by default because it has some known issues, and - /// may require a significant transition for old code. - /// - /// [placeholder lifetime]: https://doc.rust-lang.org/reference/lifetime-elision.html#lifetime-elision-in-functions - pub ELIDED_LIFETIMES_IN_PATHS, - Allow, - "hidden lifetime parameters in types are deprecated" -} - declare_lint! { /// The `bare_trait_objects` lint suggests using `dyn Trait` for trait /// objects. diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index fe068d96b7424..7aeabf9e0166f 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -621,7 +621,6 @@ pub enum BuiltinLintDiag { ident: Ident, }, MacroExpandedMacroExportsAccessedByAbsolutePaths(Span), - ElidedLifetimesInPaths(usize, Span, bool, Span), UnknownCrateTypes { span: Span, candidate: Option, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 163e4b5b7a949..0a4c688b7c62a 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2061,7 +2061,6 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { kind, count: expected_lifetimes, }; - let mut should_lint = true; for rib in self.lifetime_ribs.iter().rev() { match rib.kind { // In create-parameter mode we error here because we don't want to support @@ -2084,7 +2083,6 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { span: path_span, subdiag, }); - should_lint = false; for id in node_ids { self.record_lifetime_res( @@ -2153,20 +2151,6 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } } } - - if should_lint { - self.r.lint_buffer.buffer_lint( - lint::builtin::ELIDED_LIFETIMES_IN_PATHS, - segment_id, - elided_lifetime_span, - lint::BuiltinLintDiag::ElidedLifetimesInPaths( - expected_lifetimes, - path_span, - !segment.has_generic_args, - elided_lifetime_span, - ), - ); - } } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs index 966f117a1bf91..e026647e481af 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs @@ -1096,7 +1096,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { let generics = tcx.generics_of(def_id); let segment: Option<_> = try { - if !segment.infer_args || generics.has_impl_trait() { + if !segment.infer_args() || generics.has_impl_trait() { do yeet (); } let span = tcx.hir_span(segment.hir_id); diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 5b9b0ef30014c..9de2a0414a8d1 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1983,7 +1983,7 @@ pub fn is_expr_untyped_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) is_body_identity_function(cx, cx.tcx.hir_body(body)) }, ExprKind::Path(QPath::Resolved(_, path)) - if path.segments.iter().all(|seg| seg.infer_args) + if path.segments.iter().all(|seg| seg.infer_args()) && let Some(did) = path.res.opt_def_id() => { cx.tcx.is_diagnostic_item(sym::convert_identity, did) diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs index a24fbbc0ceab3..671764e5d9e1b 100644 --- a/src/tools/lint-docs/src/groups.rs +++ b/src/tools/lint-docs/src/groups.rs @@ -12,6 +12,7 @@ static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[ ("let-underscore", "Lints that detect wildcard let bindings that are likely to be invalid"), ("rustdoc", "Rustdoc-specific lints"), ("rust-2018-idioms", "Lints to nudge you toward idiomatic features of Rust 2018"), + ("hidden-lifetimes-in-paths", "Lints that detect the use of hidden lifetime parameters"), ("nonstandard-style", "Violation of standard naming conventions"), ("future-incompatible", "Lints that detect code that has future-compatibility problems"), ("rust-2018-compatibility", "Lints used to transition code from the 2015 edition to 2018"), @@ -32,6 +33,10 @@ static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[ ), ]; +pub fn exists(name: &str) -> bool { + GROUP_DESCRIPTIONS.iter().any(|&(n, _)| n == name) +} + type LintGroups = BTreeMap>; impl<'a> LintExtractor<'a> { diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index b33344ca5dda4..2aca890fdd01a 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -24,7 +24,7 @@ static RENAMES: &[(Level, &[(&str, &str)])] = &[ Level::Allow, &[ ("single-use-lifetime", "single-use-lifetimes"), - ("elided-lifetime-in-path", "elided-lifetimes-in-paths"), + ("elided-lifetime-in-path", "hidden-lifetimes-in-paths"), ("async-idents", "keyword-idents"), ("disjoint-capture-migration", "rust-2021-incompatible-closure-captures"), ("keyword-idents", "keyword-idents-2018"), @@ -584,9 +584,15 @@ impl<'a> LintExtractor<'a> { fn add_renamed_lints(lints: &mut Vec) { for (level, names) in RENAMES { for (from, to) in *names { + let doc = if groups::exists(to) { + format!("The lint `{from}` has been renamed to the group `{to}`.") + } else { + format!("The lint `{from}` has been renamed to [`{to}`](#{to}).") + }; + lints.push(Lint { name: from.to_string(), - doc: vec![format!("The lint `{from}` has been renamed to [`{to}`](#{to}).")], + doc: vec![doc], level: *level, path: PathBuf::new(), lineno: 0, diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index ee06707415f59..9b5db2589145e 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -1382,7 +1382,6 @@ ui/let-else/issue-100103.rs ui/let-else/issue-102317.rs ui/let-else/issue-94176.rs ui/let-else/issue-99975.rs -ui/lifetimes/auxiliary/issue-91763-aux.rs ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.rs ui/lifetimes/issue-104432-unused-lifetimes-in-expansion.rs ui/lifetimes/issue-105227.rs @@ -1415,7 +1414,6 @@ ui/lifetimes/issue-84398.rs ui/lifetimes/issue-84604.rs ui/lifetimes/issue-90170-elision-mismatch.rs ui/lifetimes/issue-90600-expected-return-static-indirect.rs -ui/lifetimes/issue-91763.rs ui/lifetimes/issue-93911.rs ui/lifetimes/issue-95023.rs ui/lifetimes/issue-97193.rs diff --git a/tests/ui/lifetimes/auxiliary/issue-91763-aux.rs b/tests/ui/lifetimes/auxiliary/issue-91763-aux.rs deleted file mode 100644 index 4e4b7f61f1ef4..0000000000000 --- a/tests/ui/lifetimes/auxiliary/issue-91763-aux.rs +++ /dev/null @@ -1,42 +0,0 @@ -//#![feature(proc_macro_diagnostic, proc_macro_span, proc_macro_def_site)] - -extern crate proc_macro; - -use proc_macro::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree}; -use std::iter::FromIterator; - -#[proc_macro_attribute] -pub fn repro(_args: TokenStream, input: TokenStream) -> TokenStream { - let call_site = Span::call_site(); - let span = input.into_iter().nth(8).unwrap().span(); - - //fn f(_: &::std::fmt::Formatter) {} - TokenStream::from_iter([ - TokenTree::Ident(Ident::new("fn", call_site)), - TokenTree::Ident(Ident::new("f", call_site)), - TokenTree::Group(Group::new( - Delimiter::Parenthesis, - TokenStream::from_iter([ - TokenTree::Ident(Ident::new("_", call_site)), - TokenTree::Punct(punct(':', Spacing::Alone, call_site)), - TokenTree::Punct(punct('&', Spacing::Alone, call_site)), - TokenTree::Punct(punct(':', Spacing::Joint, span)), - TokenTree::Punct(punct(':', Spacing::Alone, span)), - TokenTree::Ident(Ident::new("std", span)), - TokenTree::Punct(punct(':', Spacing::Joint, span)), - TokenTree::Punct(punct(':', Spacing::Alone, span)), - TokenTree::Ident(Ident::new("fmt", span)), - TokenTree::Punct(punct(':', Spacing::Joint, span)), - TokenTree::Punct(punct(':', Spacing::Alone, span)), - TokenTree::Ident(Ident::new("Formatter", span)), - ]), - )), - TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::new())), - ]) -} - -fn punct(ch: char, spacing: Spacing, span: Span) -> Punct { - let mut punct = Punct::new(ch, spacing); - punct.set_span(span); - punct -} diff --git a/tests/ui/lifetimes/elided-lint-in-mod.rs b/tests/ui/lifetimes/elided-lint-in-mod.rs deleted file mode 100644 index afe85cb607d40..0000000000000 --- a/tests/ui/lifetimes/elided-lint-in-mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -struct Foo<'a>(&'a ()); - -fn test(_: Foo) {} - -#[deny(elided_lifetimes_in_paths)] -mod w { - fn test2(_: super::Foo) {} - //~^ ERROR hidden lifetime parameters in types are deprecated -} - -fn main() {} diff --git a/tests/ui/lifetimes/elided-lint-in-mod.stderr b/tests/ui/lifetimes/elided-lint-in-mod.stderr deleted file mode 100644 index 1fee18028c66f..0000000000000 --- a/tests/ui/lifetimes/elided-lint-in-mod.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: hidden lifetime parameters in types are deprecated - --> $DIR/elided-lint-in-mod.rs:7:24 - | -LL | fn test2(_: super::Foo) {} - | -------^^^ - | | - | expected lifetime parameter - | -note: the lint level is defined here - --> $DIR/elided-lint-in-mod.rs:5:8 - | -LL | #[deny(elided_lifetimes_in_paths)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -help: indicate the anonymous lifetime - | -LL | fn test2(_: super::Foo<'_>) {} - | ++++ - -error: aborting due to 1 previous error - diff --git a/tests/ui/lifetimes/hidden-lifetimes-in-mod.rs b/tests/ui/lifetimes/hidden-lifetimes-in-mod.rs new file mode 100644 index 0000000000000..470431b8407a0 --- /dev/null +++ b/tests/ui/lifetimes/hidden-lifetimes-in-mod.rs @@ -0,0 +1,11 @@ +struct Foo<'a>(&'a ()); + +fn test(_: Foo) {} + +#[deny(hidden_lifetimes_in_paths)] +mod w { + fn test2(_: super::Foo) {} + //~^ ERROR paths containing hidden lifetime parameters are deprecated +} + +fn main() {} diff --git a/tests/ui/lifetimes/hidden-lifetimes-in-mod.stderr b/tests/ui/lifetimes/hidden-lifetimes-in-mod.stderr new file mode 100644 index 0000000000000..679f511376326 --- /dev/null +++ b/tests/ui/lifetimes/hidden-lifetimes-in-mod.stderr @@ -0,0 +1,19 @@ +error: paths containing hidden lifetime parameters are deprecated + --> $DIR/hidden-lifetimes-in-mod.rs:7:17 + | +LL | fn test2(_: super::Foo) {} + | ^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/hidden-lifetimes-in-mod.rs:5:8 + | +LL | #[deny(hidden_lifetimes_in_paths)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[deny(hidden_lifetimes_in_input_paths)]` implied by `#[deny(hidden_lifetimes_in_paths)]` +help: indicate the anonymous lifetime + | +LL | fn test2(_: super::Foo<'_>) {} + | ++++ + +error: aborting due to 1 previous error + diff --git a/tests/ui/lifetimes/hidden-lifetimes-in-type-paths.rs b/tests/ui/lifetimes/hidden-lifetimes-in-type-paths.rs new file mode 100644 index 0000000000000..d2b555bea073a --- /dev/null +++ b/tests/ui/lifetimes/hidden-lifetimes-in-type-paths.rs @@ -0,0 +1,78 @@ +#![deny(hidden_lifetimes_in_type_paths)] + +struct ContainsLifetime<'a>(&'a u8); + +impl<'a> ContainsLifetime<'a> { + fn use_it() {} +} + +struct ContainsLifetimeAndType<'a, T>(&'a T); + +impl<'a, T> ContainsLifetimeAndType<'a, T> { + fn use_it() {} +} + +fn use_via_turbofish() {} + +trait UseViaTrait { + fn use_it() {} +} + +impl UseViaTrait for ContainsLifetime<'_> {} + +trait TraitWithLifetime<'a> { + fn use_it() {} +} + +impl<'a> TraitWithLifetime<'a> for u8 {} + +enum EnumWithType { + VariantStructLike { v: T }, + VariantTupleLike(T), + VariantUnit, +} + +type TypeAliasWithLifetime<'a> = EnumWithType<&'a u8>; + +// ========== + +static USE_VIA_STATIC: ContainsLifetime = ContainsLifetime(&42); +//~^ ERROR hidden lifetime parameters + +fn main() { + use_via_turbofish::(); + //~^ ERROR hidden lifetime parameters + + let _use_via_binding: ContainsLifetime; + //~^ ERROR hidden lifetime parameters + + ::use_it(); + //~^ ERROR hidden lifetime parameters + + ::use_it(); + //~^ ERROR hidden lifetime parameters + + ContainsLifetime::use_it(); + + ContainsLifetimeAndType::::use_it(); + + ::use_it(); +} + +impl TypeAliasWithLifetime<'_> { + fn use_via_match(self) { + match self { + TypeAliasWithLifetime::VariantStructLike { .. } => (), + TypeAliasWithLifetime::VariantTupleLike(_) => (), + TypeAliasWithLifetime::VariantUnit => (), + } + } + + fn use_via_create(v: u8) -> Self { + match v { + 0 => TypeAliasWithLifetime::VariantStructLike { v: &42 }, + 1 => TypeAliasWithLifetime::VariantTupleLike(&42), + _ => TypeAliasWithLifetime::VariantUnit, + } + } +} diff --git a/tests/ui/lifetimes/hidden-lifetimes-in-type-paths.stderr b/tests/ui/lifetimes/hidden-lifetimes-in-type-paths.stderr new file mode 100644 index 0000000000000..f98935921c130 --- /dev/null +++ b/tests/ui/lifetimes/hidden-lifetimes-in-type-paths.stderr @@ -0,0 +1,62 @@ +error: paths containing hidden lifetime parameters are deprecated + --> $DIR/hidden-lifetimes-in-type-paths.rs:39:24 + | +LL | static USE_VIA_STATIC: ContainsLifetime = ContainsLifetime(&42); + | ^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/hidden-lifetimes-in-type-paths.rs:1:9 + | +LL | #![deny(hidden_lifetimes_in_type_paths)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: indicate the anonymous lifetime + | +LL | static USE_VIA_STATIC: ContainsLifetime<'_> = ContainsLifetime(&42); + | ++++ + +error: paths containing hidden lifetime parameters are deprecated + --> $DIR/hidden-lifetimes-in-type-paths.rs:43:25 + | +LL | use_via_turbofish::(); + | ^^^^^^^^^^^^^^^^ + | +help: indicate the anonymous lifetime + | +LL | use_via_turbofish::>(); + | ++++ + +error: paths containing hidden lifetime parameters are deprecated + --> $DIR/hidden-lifetimes-in-type-paths.rs:46:27 + | +LL | let _use_via_binding: ContainsLifetime; + | ^^^^^^^^^^^^^^^^ + | +help: indicate the anonymous lifetime + | +LL | let _use_via_binding: ContainsLifetime<'_>; + | ++++ + +error: paths containing hidden lifetime parameters are deprecated + --> $DIR/hidden-lifetimes-in-type-paths.rs:49:6 + | +LL | ::use_it(); + | ^^^^^^^^^^^^^^^^ + | +help: indicate the anonymous lifetime + | +LL | as UseViaTrait>::use_it(); + | ++++ + +error: paths containing hidden lifetime parameters are deprecated + --> $DIR/hidden-lifetimes-in-type-paths.rs:52:6 + | +LL | ::use_it(); + | ^^^^^^^^^^^^^^^^ + | +help: indicate the anonymous lifetime + | +LL | >::use_it(); + | ++++ + +error: aborting due to 5 previous errors + diff --git a/tests/ui/lifetimes/issue-91763.rs b/tests/ui/lifetimes/issue-91763.rs deleted file mode 100644 index 6abb64db5feba..0000000000000 --- a/tests/ui/lifetimes/issue-91763.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ proc-macro: issue-91763-aux.rs - -#![deny(elided_lifetimes_in_paths)] - -extern crate issue_91763_aux; - -#[issue_91763_aux::repro] -fn f() -> Ptr; -//~^ ERROR hidden lifetime parameters in types are deprecated - -fn main() {} diff --git a/tests/ui/lifetimes/issue-91763.stderr b/tests/ui/lifetimes/issue-91763.stderr deleted file mode 100644 index f7293ed809c3a..0000000000000 --- a/tests/ui/lifetimes/issue-91763.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error: hidden lifetime parameters in types are deprecated - --> $DIR/issue-91763.rs:8:20 - | -LL | fn f() -> Ptr; - | ^ expected lifetime parameter - | -note: the lint level is defined here - --> $DIR/issue-91763.rs:3:9 - | -LL | #![deny(elided_lifetimes_in_paths)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -help: indicate the anonymous lifetime - | -LL | fn f() -> Ptr<'_>; - | ++++ - -error: aborting due to 1 previous error - diff --git a/tests/ui/lint/force-warn/allowed-by-default-lint.rs b/tests/ui/lint/force-warn/allowed-by-default-lint.rs index f0c9663c0d3a2..7f290dac230c2 100644 --- a/tests/ui/lint/force-warn/allowed-by-default-lint.rs +++ b/tests/ui/lint/force-warn/allowed-by-default-lint.rs @@ -1,5 +1,5 @@ // --force-warn $LINT causes $LINT (which is allow-by-default) to warn -//@ compile-flags: --force-warn elided_lifetimes_in_paths +//@ compile-flags: --force-warn hidden_lifetimes_in_paths //@ check-pass struct Foo<'a> { @@ -7,6 +7,6 @@ struct Foo<'a> { } fn foo(x: &Foo) {} -//~^ WARN hidden lifetime parameters in types are deprecated +//~^ WARN paths containing hidden lifetime parameters are deprecated fn main() {} diff --git a/tests/ui/lint/force-warn/allowed-by-default-lint.stderr b/tests/ui/lint/force-warn/allowed-by-default-lint.stderr index ac98b5896ca7b..26dae7dbe7e73 100644 --- a/tests/ui/lint/force-warn/allowed-by-default-lint.stderr +++ b/tests/ui/lint/force-warn/allowed-by-default-lint.stderr @@ -1,10 +1,10 @@ -warning: hidden lifetime parameters in types are deprecated +warning: paths containing hidden lifetime parameters are deprecated --> $DIR/allowed-by-default-lint.rs:9:12 | LL | fn foo(x: &Foo) {} - | ^^^ expected lifetime parameter + | ^^^ | - = note: requested on the command line with `--force-warn elided-lifetimes-in-paths` + = note: `--force-warn hidden-lifetimes-in-input-paths` implied by `--force-warn hidden-lifetimes-in-paths` help: indicate the anonymous lifetime | LL | fn foo(x: &Foo<'_>) {} diff --git a/tests/ui/lint/reasons-erroneous.rs b/tests/ui/lint/reasons-erroneous.rs index 0aa46953bf1ac..3a17245750a78 100644 --- a/tests/ui/lint/reasons-erroneous.rs +++ b/tests/ui/lint/reasons-erroneous.rs @@ -12,7 +12,7 @@ #![warn(unsafe_code, blerp = "or in league with robbers have reversed the signposts")] //~^ ERROR malformed lint attribute //~| NOTE bad attribute argument -#![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))] +#![warn(hidden_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))] //~^ ERROR malformed lint attribute //~| NOTE bad attribute argument #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")] diff --git a/tests/ui/lint/reasons-erroneous.stderr b/tests/ui/lint/reasons-erroneous.stderr index fcff88d8e0fa7..5dccd64f77927 100644 --- a/tests/ui/lint/reasons-erroneous.stderr +++ b/tests/ui/lint/reasons-erroneous.stderr @@ -25,7 +25,7 @@ LL | #![warn(unsafe_code, blerp = "or in league with robbers have reversed the s error[E0452]: malformed lint attribute input --> $DIR/reasons-erroneous.rs:15:36 | -LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))] +LL | #![warn(hidden_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument error[E0452]: malformed lint attribute input diff --git a/tests/ui/lint/reasons.rs b/tests/ui/lint/reasons.rs index 917e7539aaed3..f75d27aa2e883 100644 --- a/tests/ui/lint/reasons.rs +++ b/tests/ui/lint/reasons.rs @@ -1,6 +1,6 @@ //@ check-pass -#![warn(elided_lifetimes_in_paths, +#![warn(hidden_lifetimes_in_paths, //~^ NOTE the lint level is defined here reason = "explicit anonymous lifetimes aid reasoning about ownership")] #![warn( @@ -17,8 +17,8 @@ pub struct CheaterDetectionMechanism {} impl fmt::Debug for CheaterDetectionMechanism { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - //~^ WARN hidden lifetime parameters in types are deprecated - //~| NOTE expected lifetime parameter + //~^ WARN paths containing hidden lifetime parameters are deprecated + //~| NOTE implied by //~| NOTE explicit anonymous lifetimes aid //~| HELP indicate the anonymous lifetime fmt.debug_struct("CheaterDetectionMechanism").finish() diff --git a/tests/ui/lint/reasons.stderr b/tests/ui/lint/reasons.stderr index 8028785ab94be..4fb73d474bc99 100644 --- a/tests/ui/lint/reasons.stderr +++ b/tests/ui/lint/reasons.stderr @@ -1,17 +1,16 @@ -warning: hidden lifetime parameters in types are deprecated - --> $DIR/reasons.rs:19:34 +warning: paths containing hidden lifetime parameters are deprecated + --> $DIR/reasons.rs:19:29 | LL | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - | -----^^^^^^^^^ - | | - | expected lifetime parameter + | ^^^^^^^^^^^^^^ | = note: explicit anonymous lifetimes aid reasoning about ownership note: the lint level is defined here --> $DIR/reasons.rs:3:9 | -LL | #![warn(elided_lifetimes_in_paths, +LL | #![warn(hidden_lifetimes_in_paths, | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(hidden_lifetimes_in_input_paths)]` implied by `#[warn(hidden_lifetimes_in_paths)]` help: indicate the anonymous lifetime | LL | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {