diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 9899ee03a513a..724b51ecf9cc7 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -44,6 +44,7 @@ use hir::{BodyId, HirId}; use rustc_abi::ExternAbi; use rustc_ast::*; use rustc_errors::ErrorGuaranteed; +use rustc_hir::TySource; use rustc_hir::def_id::DefId; use rustc_middle::span_bug; use rustc_middle::ty::{Asyncness, ResolverAstLowering}; @@ -174,12 +175,14 @@ impl<'hir> LoweringContext<'_, 'hir> { hir_id: self.next_id(), kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Input(arg)), span, + source: TySource::Other, })); let output = self.arena.alloc(hir::Ty { hir_id: self.next_id(), kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Output), span, + source: TySource::Other, }); self.arena.alloc(hir::FnDecl { diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index df4fd2ef52fe7..ccdca7acbba48 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -6,9 +6,8 @@ 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::HirId; use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{self as hir, HirId, TySource}; use rustc_middle::span_bug; use rustc_middle::ty::TyCtxt; use rustc_session::errors::report_lit_error; @@ -759,6 +758,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir_id: self.next_id(), kind: hir::TyKind::Path(resume_ty), span: unstable_span, + source: TySource::Other, }; let inputs = arena_vec![self; input_ty]; diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 958a6917dff87..402a9c13a7757 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -5,7 +5,7 @@ use rustc_ast::*; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; -use rustc_hir::{self as hir, HirId, IsAnonInPath, PredicateOrigin}; +use rustc_hir::{self as hir, HirId, LifetimeSource, PredicateOrigin}; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_span::edit_distance::find_best_match_for_name; @@ -1861,7 +1861,8 @@ impl<'hir> LoweringContext<'_, 'hir> { } GenericParamKind::Lifetime => { let lt_id = self.next_node_id(); - let lifetime = self.new_named_lifetime(id, lt_id, ident, IsAnonInPath::No); + let lifetime = + self.new_named_lifetime(id, lt_id, ident, LifetimeSource::Other, ident.into()); hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate { lifetime, bounds, @@ -1894,7 +1895,11 @@ impl<'hir> LoweringContext<'_, 'hir> { }), WherePredicateKind::RegionPredicate(WhereRegionPredicate { lifetime, bounds }) => { hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate { - lifetime: self.lower_lifetime(lifetime), + lifetime: self.lower_lifetime( + lifetime, + LifetimeSource::Other, + lifetime.ident.into(), + ), bounds: self.lower_param_bounds( bounds, ImplTraitContext::Disallowed(ImplTraitPosition::Bound), diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 6aa6a18ee9a72..79f5dd675580d 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -55,8 +55,8 @@ use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey}; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId}; use rustc_hir::{ - self as hir, ConstArg, GenericArg, HirId, IsAnonInPath, ItemLocalMap, LangItem, ParamName, - TraitCandidate, + self as hir, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, LifetimeSource, + LifetimeSyntax, ParamName, TraitCandidate, TySource, }; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_macros::extension; @@ -1080,7 +1080,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { itctx: ImplTraitContext, ) -> hir::GenericArg<'hir> { match arg { - ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(lt)), + ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime( + lt, + LifetimeSource::Path { with_angle_brackets: true }, + lt.ident.into(), + )), ast::GenericArg::Type(ty) => { // We cannot just match on `TyKind::Infer` as `(_)` is represented as // `TyKind::Paren(TyKind::Infer)` and should also be lowered to `GenericArg::Infer` @@ -1168,7 +1172,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { bounds, TaggedRef::new(lifetime_bound, TraitObjectSyntax::None), ); - return hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.next_id() }; + return hir::Ty { + kind, + span: self.lower_span(t.span), + hir_id: self.next_id(), + source: TySource::Other, + }; } let id = self.lower_node_id(t.id); @@ -1185,7 +1194,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn ty(&mut self, span: Span, kind: hir::TyKind<'hir>) -> hir::Ty<'hir> { - hir::Ty { hir_id: self.next_id(), kind, span: self.lower_span(span) } + hir::Ty { + hir_id: self.next_id(), + kind, + span: self.lower_span(span), + source: TySource::Other, + } } fn ty_tup(&mut self, span: Span, tys: &'hir [hir::Ty<'hir>]) -> hir::Ty<'hir> { @@ -1199,38 +1213,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)), TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)), TyKind::Ref(region, mt) => { - let region = region.unwrap_or_else(|| { - let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) = - self.resolver.get_lifetime_res(t.id) - { - debug_assert_eq!(start.plus(1), end); - start - } else { - self.next_node_id() - }; - let span = self.tcx.sess.source_map().start_point(t.span).shrink_to_hi(); - Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id } - }); - let lifetime = self.lower_lifetime(®ion); + let lifetime = self.lower_ty_direct_lifetime(t, *region); hir::TyKind::Ref(lifetime, self.lower_mt(mt, itctx)) } TyKind::PinnedRef(region, mt) => { - let region = region.unwrap_or_else(|| { - let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) = - self.resolver.get_lifetime_res(t.id) - { - debug_assert_eq!(start.plus(1), end); - start - } else { - self.next_node_id() - }; - let span = self.tcx.sess.source_map().start_point(t.span).shrink_to_hi(); - Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id } - }); - let lifetime = self.lower_lifetime(®ion); + let lifetime = self.lower_ty_direct_lifetime(t, *region); let kind = hir::TyKind::Ref(lifetime, self.lower_mt(mt, itctx)); let span = self.lower_span(t.span); - let arg = hir::Ty { kind, span, hir_id: self.next_id() }; + let arg = hir::Ty { kind, span, hir_id: self.next_id(), source: TySource::Other }; let args = self.arena.alloc(hir::GenericArgs { args: self.arena.alloc([hir::GenericArg::Type(self.arena.alloc(arg))]), constraints: &[], @@ -1303,7 +1293,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } GenericBound::Outlives(lifetime) => { if lifetime_bound.is_none() { - lifetime_bound = Some(this.lower_lifetime(lifetime)); + lifetime_bound = Some(this.lower_lifetime( + lifetime, + LifetimeSource::Other, + lifetime.ident.into(), + )); } None } @@ -1391,7 +1385,37 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { TyKind::Dummy => panic!("`TyKind::Dummy` should never be lowered"), }; - hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.lower_node_id(t.id) } + hir::Ty { + kind, + span: self.lower_span(t.span), + hir_id: self.lower_node_id(t.id), + source: TySource::Other, + } + } + + fn lower_ty_direct_lifetime( + &mut self, + t: &Ty, + region: Option, + ) -> &'hir hir::Lifetime { + let (region, syntax) = match region { + Some(region) => (region, region.ident.into()), + + None => { + let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) = + self.resolver.get_lifetime_res(t.id) + { + debug_assert_eq!(start.plus(1), end); + start + } else { + self.next_node_id() + }; + let span = self.tcx.sess.source_map().start_point(t.span).shrink_to_hi(); + let region = Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id }; + (region, LifetimeSyntax::Hidden) + } + }; + self.lower_lifetime(®ion, LifetimeSource::Reference, syntax) } /// Lowers a `ReturnPositionOpaqueTy` (`-> impl Trait`) or a `TypeAliasesOpaqueTy` (`type F = @@ -1475,9 +1499,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { precise_capturing_args: &[PreciseCapturingArg], ) -> &'hir [hir::PreciseCapturingArg<'hir>] { self.arena.alloc_from_iter(precise_capturing_args.iter().map(|arg| match arg { - PreciseCapturingArg::Lifetime(lt) => { - hir::PreciseCapturingArg::Lifetime(self.lower_lifetime(lt)) - } + PreciseCapturingArg::Lifetime(lt) => hir::PreciseCapturingArg::Lifetime( + self.lower_lifetime(lt, LifetimeSource::PreciseCapturing, lt.ident.into()), + ), PreciseCapturingArg::Arg(path, id) => { let [segment] = path.segments.as_slice() else { panic!(); @@ -1740,9 +1764,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) -> hir::GenericBound<'hir> { match tpb { GenericBound::Trait(p) => hir::GenericBound::Trait(self.lower_poly_trait_ref(p, itctx)), - GenericBound::Outlives(lifetime) => { - hir::GenericBound::Outlives(self.lower_lifetime(lifetime)) - } + GenericBound::Outlives(lifetime) => hir::GenericBound::Outlives(self.lower_lifetime( + lifetime, + LifetimeSource::OutlivesBound, + lifetime.ident.into(), + )), GenericBound::Use(args, span) => hir::GenericBound::Use( self.lower_precise_capturing_args(args), self.lower_span(*span), @@ -1750,12 +1776,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - fn lower_lifetime(&mut self, l: &Lifetime) -> &'hir hir::Lifetime { - self.new_named_lifetime(l.id, l.id, l.ident, IsAnonInPath::No) + fn lower_lifetime( + &mut self, + l: &Lifetime, + source: LifetimeSource, + syntax: LifetimeSyntax, + ) -> &'hir hir::Lifetime { + self.new_named_lifetime(l.id, l.id, l.ident, source, syntax) } - fn lower_lifetime_anon_in_path(&mut self, id: NodeId, span: Span) -> &'hir hir::Lifetime { - self.new_named_lifetime(id, id, Ident::new(kw::UnderscoreLifetime, span), IsAnonInPath::Yes) + fn lower_lifetime_hidden_in_path( + &mut self, + id: NodeId, + span: Span, + with_angle_brackets: bool, + ) -> &'hir hir::Lifetime { + self.new_named_lifetime( + id, + id, + Ident::new(kw::UnderscoreLifetime, span), + LifetimeSource::Path { with_angle_brackets }, + LifetimeSyntax::Hidden, + ) } #[instrument(level = "debug", skip(self))] @@ -1764,7 +1806,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { id: NodeId, new_id: NodeId, ident: Ident, - is_anon_in_path: IsAnonInPath, + source: LifetimeSource, + syntax: LifetimeSyntax, ) -> &'hir hir::Lifetime { debug_assert_ne!(ident.name, kw::Empty); let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error); @@ -1789,17 +1832,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } }; - #[cfg(debug_assertions)] - if is_anon_in_path == IsAnonInPath::Yes { - debug_assert_eq!(ident.name, kw::UnderscoreLifetime); - } - debug!(?res); self.arena.alloc(hir::Lifetime::new( self.lower_node_id(new_id), self.lower_ident(ident), res, - is_anon_in_path, + source, + syntax, )) } @@ -2350,7 +2389,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - fn ty_path(&mut self, mut hir_id: HirId, span: Span, qpath: hir::QPath<'hir>) -> hir::Ty<'hir> { + fn ty_path(&mut self, hir_id: HirId, span: Span, qpath: hir::QPath<'hir>) -> hir::Ty<'hir> { + self.ty_path_with_source(hir_id, span, qpath, TySource::Other) + } + + fn ty_path_with_source( + &mut self, + mut hir_id: HirId, + span: Span, + qpath: hir::QPath<'hir>, + source: TySource, + ) -> hir::Ty<'hir> { let kind = match qpath { hir::QPath::Resolved(None, path) => { // Turn trait object paths into `TyKind::TraitObject` instead. @@ -2377,7 +2426,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { _ => hir::TyKind::Path(qpath), }; - hir::Ty { hir_id, kind, span: self.lower_span(span) } + hir::Ty { hir_id, kind, span: self.lower_span(span), source } } /// Invoked to create the lifetime argument(s) for an elided trait object @@ -2389,7 +2438,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.next_id(), Ident::new(kw::UnderscoreLifetime, self.lower_span(span)), hir::LifetimeName::ImplicitObjectLifetimeDefault, - IsAnonInPath::No, + LifetimeSource::Other, + LifetimeSyntax::Hidden, ); debug!("elided_dyn_bound: r={:?}", r); self.arena.alloc(r) diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index c464c159c34cd..5d7d72f2e0ae8 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -1,10 +1,9 @@ use std::sync::Arc; use rustc_ast::{self as ast, *}; -use rustc_hir as hir; -use rustc_hir::GenericArg; use rustc_hir::def::{DefKind, PartialRes, Res}; use rustc_hir::def_id::DefId; +use rustc_hir::{self as hir, GenericArg, TySource}; use rustc_middle::span_bug; use rustc_session::parse::add_feature_diagnostics; use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym}; @@ -170,7 +169,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // 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_with_source( + new_id, + path.span, + hir::QPath::Resolved(qself, path), + TySource::ImplicitSelf, + )) }; // Anything after the base path are associated "extensions", @@ -433,24 +437,29 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Note: these spans are used for diagnostics when they can't be inferred. // See rustc_resolve::late::lifetimes::LifetimeContext::add_missing_lifetime_specifiers_label - let elided_lifetime_span = if generic_args.span.is_empty() { + let (elided_lifetime_span, with_angle_brackets) = if generic_args.span.is_empty() { // If there are no brackets, use the identifier span. // HACK: we use find_ancestor_inside to properly suggest elided spans in paths // originating from macros, since the segment's span might be from a macro arg. - segment_ident_span.find_ancestor_inside(path_span).unwrap_or(path_span) + (segment_ident_span.find_ancestor_inside(path_span).unwrap_or(path_span), false) } else if generic_args.is_empty() { // If there are brackets, but not generic arguments, then use the opening bracket - generic_args.span.with_hi(generic_args.span.lo() + BytePos(1)) + (generic_args.span.with_hi(generic_args.span.lo() + BytePos(1)), true) } else { // Else use an empty span right after the opening bracket. - generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo() + (generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo(), true) }; generic_args.args.insert_many( 0, (start.as_u32()..end.as_u32()).map(|i| { let id = NodeId::from_u32(i); - let l = self.lower_lifetime_anon_in_path(id, elided_lifetime_span); + + let l = self.lower_lifetime_hidden_in_path( + id, + elided_lifetime_span, + with_angle_brackets, + ); GenericArg::Lifetime(l) }), ); diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 8e53e600f7ac6..bd139e2eb3f15 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -2,7 +2,7 @@ use rustc_ast::ParamKindOrd; use rustc_errors::codes::*; -use rustc_errors::{Applicability, Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic}; +use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Ident, Span, Symbol}; @@ -394,11 +394,7 @@ pub(crate) struct EmptyLabelManySpans(pub Vec); // The derive for `Vec` does multiple calls to `span_label`, adding commas between each impl Subdiagnostic for EmptyLabelManySpans { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.span_labels(self.0, ""); } } @@ -749,11 +745,7 @@ pub(crate) struct StableFeature { } impl Subdiagnostic for StableFeature { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("name", self.name); diag.arg("since", self.since); diag.help(fluent::ast_passes_stable_since); 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_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 4bbe212f4296c..3fb24434995db 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -1,7 +1,7 @@ use rustc_errors::codes::*; use rustc_errors::{ Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan, SingleLabelManySpans, - SubdiagMessageOp, Subdiagnostic, + Subdiagnostic, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Ident, Span, Symbol}; @@ -691,13 +691,9 @@ pub(crate) struct FormatUnusedArg { // Allow the singular form to be a subdiagnostic of the multiple-unused // form of diagnostic. impl Subdiagnostic for FormatUnusedArg { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("named", self.named); - let msg = f(diag, crate::fluent_generated::builtin_macros_format_unused_arg.into()); + let msg = diag.eagerly_translate(crate::fluent_generated::builtin_macros_format_unused_arg); diag.span_label(self.span, msg); } } diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index e2675e2f4c900..6472aaa575812 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -6,7 +6,7 @@ use rustc_abi::WrappingRange; use rustc_errors::codes::*; use rustc_errors::{ Diag, DiagArgValue, DiagCtxtHandle, DiagMessage, Diagnostic, EmissionGuarantee, Level, - MultiSpan, SubdiagMessageOp, Subdiagnostic, + MultiSpan, Subdiagnostic, }; use rustc_hir::ConstContext; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; @@ -290,11 +290,7 @@ pub struct FrameNote { } impl Subdiagnostic for FrameNote { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("times", self.times); diag.arg("where_", self.where_); diag.arg("instance", self.instance); @@ -302,7 +298,7 @@ impl Subdiagnostic for FrameNote { if self.has_label && !self.span.is_dummy() { span.push_span_label(self.span, fluent::const_eval_frame_note_last); } - let msg = f(diag, fluent::const_eval_frame_note.into()); + let msg = diag.eagerly_translate(fluent::const_eval_frame_note); diag.span_note(span, msg); } } diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 794502d7aaee3..6ab80129b5fb2 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -181,22 +181,9 @@ where Self: Sized, { /// Add a subdiagnostic to an existing diagnostic. - fn add_to_diag(self, diag: &mut Diag<'_, G>) { - self.add_to_diag_with(diag, &|_, m| m); - } - - /// Add a subdiagnostic to an existing diagnostic where `f` is invoked on every message used - /// (to optionally perform eager translation). - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ); + fn add_to_diag(self, diag: &mut Diag<'_, G>); } -pub trait SubdiagMessageOp = - Fn(&mut Diag<'_, G>, SubdiagMessage) -> SubdiagMessage; - /// Trait implemented by lint types. This should not be implemented manually. Instead, use /// `#[derive(LintDiagnostic)]` -- see [rustc_macros::LintDiagnostic]. #[rustc_diagnostic_item = "LintDiagnostic"] @@ -1227,15 +1214,16 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { /// interpolated variables). #[rustc_lint_diagnostics] pub fn subdiagnostic(&mut self, subdiagnostic: impl Subdiagnostic) -> &mut Self { - let dcx = self.dcx; - subdiagnostic.add_to_diag_with(self, &|diag, msg| { - let args = diag.args.iter(); - let msg = diag.subdiagnostic_message_to_diagnostic_message(msg); - dcx.eagerly_translate(msg, args) - }); + subdiagnostic.add_to_diag(self); self } + pub fn eagerly_translate(&self, msg: impl Into) -> SubdiagMessage { + let args = self.args.iter(); + let msg = self.subdiagnostic_message_to_diagnostic_message(msg.into()); + self.dcx.eagerly_translate(msg, args) + } + with_fn! { with_span, /// Add a span. #[rustc_lint_diagnostics] diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index cb2e1769fa1cf..8b59ba9984c10 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -19,7 +19,7 @@ use {rustc_ast as ast, rustc_hir as hir}; use crate::diagnostic::DiagLocation; use crate::{ Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, ErrCode, IntoDiagArg, Level, - SubdiagMessageOp, Subdiagnostic, fluent_generated as fluent, + Subdiagnostic, fluent_generated as fluent, }; pub struct DiagArgFromDisplay<'a>(pub &'a dyn fmt::Display); @@ -384,11 +384,7 @@ pub struct SingleLabelManySpans { pub label: &'static str, } impl Subdiagnostic for SingleLabelManySpans { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.span_labels(self.spans, self.label); } } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index f5f7618285e1f..80374dc154935 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -47,7 +47,7 @@ pub use codes::*; pub use diagnostic::{ BugAbort, Diag, DiagArg, DiagArgMap, DiagArgName, DiagArgValue, DiagInner, DiagStyledString, Diagnostic, EmissionGuarantee, FatalAbort, IntoDiagArg, LintDiagnostic, StringPart, Subdiag, - SubdiagMessageOp, Subdiagnostic, + Subdiagnostic, }; pub use diagnostic_impls::{ DiagArgFromDisplay, DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter, diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index dc00b52a59360..e212139954364 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -845,12 +845,7 @@ pub enum LifetimeRes { /// late resolution. Those lifetimes will be inferred by typechecking. Infer, /// `'static` lifetime. - Static { - /// We do not want to emit `elided_named_lifetimes` - /// when we are inside of a const item or a static, - /// because it would get too annoying. - suppress_elision_warning: bool, - }, + Static, /// Resolution failure. Error, /// HACK: This is used to recover the NodeId of an elided lifetime. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index c61477951c920..f3c8c8121420c 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -36,42 +36,94 @@ pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId}; use crate::intravisit::{FnKind, VisitorExt}; #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)] -pub enum IsAnonInPath { - No, - Yes, +pub enum LifetimeSource { + /// `&'_ Type` + Reference, + + /// `ContainsLifetime<'_>` + Path { with_angle_brackets: bool }, + + /// impl Trait + '_ + OutlivesBound, + + /// impl Trait + use<'_> + PreciseCapturing, + + /// Details not yet needed. Feel free to give useful + /// categorization to these usages. + Other, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)] +pub enum LifetimeSyntax { + /// `&Type` + Hidden, + + /// `&'_ Type` + Anonymous, + + /// `&'a Type` + Named, +} + +impl From for LifetimeSyntax { + fn from(ident: Ident) -> Self { + let name = ident.name; + + if name == kw::Empty { + LifetimeSyntax::Hidden + } else if name == kw::UnderscoreLifetime { + LifetimeSyntax::Anonymous + } else { + debug_assert!(name.as_str().starts_with('\'')); + LifetimeSyntax::Named + } + } } /// A lifetime. The valid field combinations are non-obvious. The following /// example shows some of them. See also the comments on `LifetimeName`. /// ``` /// #[repr(C)] -/// struct S<'a>(&'a u32); // res=Param, name='a, IsAnonInPath::No +/// struct S<'a>(&'a u32); // res=Param, name='a, source=Reference, syntax=Named /// unsafe extern "C" { -/// fn f1(s: S); // res=Param, name='_, IsAnonInPath::Yes -/// fn f2(s: S<'_>); // res=Param, name='_, IsAnonInPath::No -/// fn f3<'a>(s: S<'a>); // res=Param, name='a, IsAnonInPath::No +/// fn f1(s: S); // res=Param, name='_, source=Path, syntax=Hidden +/// fn f2(s: S<'_>); // res=Param, name='_, source=Path, syntax=Anonymous +/// fn f3<'a>(s: S<'a>); // res=Param, name='a, source=Path, syntax=Named /// } /// -/// struct St<'a> { x: &'a u32 } // res=Param, name='a, IsAnonInPath::No +/// struct St<'a> { x: &'a u32 } // res=Param, name='a, source=Reference, syntax=Named /// fn f() { -/// _ = St { x: &0 }; // res=Infer, name='_, IsAnonInPath::Yes -/// _ = St::<'_> { x: &0 }; // res=Infer, name='_, IsAnonInPath::No +/// _ = St { x: &0 }; // res=Infer, name='_, source=Path, syntax=Hidden +/// _ = St::<'_> { x: &0 }; // res=Infer, name='_, source=Path, syntax=Anonymous /// } /// -/// struct Name<'a>(&'a str); // res=Param, name='a, IsAnonInPath::No -/// const A: Name = Name("a"); // res=Static, name='_, IsAnonInPath::Yes -/// const B: &str = ""; // res=Static, name='_, IsAnonInPath::No -/// static C: &'_ str = ""; // res=Static, name='_, IsAnonInPath::No -/// static D: &'static str = ""; // res=Static, name='static, IsAnonInPath::No +/// struct Name<'a>(&'a str); // res=Param, name='a, source=Reference, syntax=Named +/// const A: Name = Name("a"); // res=Static, name='_, source=Path, syntax=Hidden +/// const B: &str = ""; // res=Static, name='_, source=Reference, syntax=Hidden +/// static C: &'_ str = ""; // res=Static, name='_, source=Reference, syntax=Anonymous +/// static D: &'static str = ""; // res=Static, name='static, source=Reference, syntax=Named /// /// trait Tr {} -/// fn tr(_: Box) {} // res=ImplicitObjectLifetimeDefault, name='_, IsAnonInPath::No +/// fn tr(_: Box) {} // res=ImplicitObjectLifetimeDefault, name='_, source=Other, syntax=Hidden +/// +/// fn capture_outlives<'a>() -> +/// impl FnOnce() + 'a // res=Param, ident='a, source=OutlivesBound, syntax=Named +/// { +/// || {} +/// } +/// +/// fn capture_precise<'a>() -> +/// impl FnOnce() + use<'a> // res=Param, ident='a, source=PreciseCapturing, syntax=Named +/// { +/// || {} +/// } /// /// // (commented out because these cases trigger errors) -/// // struct S1<'a>(&'a str); // res=Param, name='a, IsAnonInPath::No -/// // struct S2(S1); // res=Error, name='_, IsAnonInPath::Yes -/// // struct S3(S1<'_>); // res=Error, name='_, IsAnonInPath::No -/// // struct S4(S1<'a>); // res=Error, name='a, IsAnonInPath::No +/// // struct S1<'a>(&'a str); // res=Param, name='a, source=Reference, syntax=Named +/// // struct S2(S1); // res=Error, name='_, source=Path, syntax=Hidden +/// // struct S3(S1<'_>); // res=Error, name='_, source=Path, syntax=Anonymous +/// // struct S4(S1<'a>); // res=Error, name='a, source=Path, syntax=Named /// ``` #[derive(Debug, Copy, Clone, HashStable_Generic)] pub struct Lifetime { @@ -88,7 +140,8 @@ pub struct Lifetime { /// Is the lifetime anonymous and in a path? Used only for error /// suggestions. See `Lifetime::suggestion` for example use. - pub is_anon_in_path: IsAnonInPath, + pub source: LifetimeSource, + pub syntax: LifetimeSyntax, } #[derive(Debug, Copy, Clone, HashStable_Generic)] @@ -129,7 +182,7 @@ impl ParamName { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)] pub enum LifetimeName { /// User-given names or fresh (synthetic) names. Param(LocalDefId), @@ -185,9 +238,10 @@ impl Lifetime { hir_id: HirId, ident: Ident, res: LifetimeName, - is_anon_in_path: IsAnonInPath, + source: LifetimeSource, + syntax: LifetimeSyntax, ) -> Lifetime { - let lifetime = Lifetime { hir_id, ident, res, is_anon_in_path }; + let lifetime = Lifetime { hir_id, ident, res, source, syntax }; // Sanity check: elided lifetimes form a strict subset of anonymous lifetimes. #[cfg(debug_assertions)] @@ -209,23 +263,44 @@ impl Lifetime { self.ident.name == kw::UnderscoreLifetime } + pub fn is_syntactically_hidden(&self) -> bool { + matches!(self.syntax, LifetimeSyntax::Hidden) + } + + pub fn is_syntactically_anonymous(&self) -> bool { + matches!(self.syntax, LifetimeSyntax::Anonymous) + } + + pub fn is_static(&self) -> bool { + self.res == LifetimeName::Static + } + pub fn suggestion(&self, new_lifetime: &str) -> (Span, String) { + use LifetimeSource::*; + use LifetimeSyntax::*; + debug_assert!(new_lifetime.starts_with('\'')); - match (self.is_anon_in_path, self.ident.span.is_empty()) { + match (self.syntax, self.source) { + // The user wrote `'a` or `'_`. + (Named | Anonymous, _) => (self.ident.span, format!("{new_lifetime}")), + // The user wrote `Path`, and omitted the `'_,`. - (IsAnonInPath::Yes, true) => (self.ident.span, format!("{new_lifetime}, ")), + (Hidden, Path { with_angle_brackets: true }) => { + (self.ident.span, format!("{new_lifetime}, ")) + } // The user wrote `Path` and omitted the `<'_>`. - (IsAnonInPath::Yes, false) => { + (Hidden, Path { with_angle_brackets: false }) => { (self.ident.span.shrink_to_hi(), format!("<{new_lifetime}>")) } // The user wrote `&type` or `&mut type`. - (IsAnonInPath::No, true) => (self.ident.span, format!("{new_lifetime} ")), + (Hidden, Reference) => (self.ident.span, format!("{new_lifetime} ")), - // The user wrote `'a` or `'_`. - (IsAnonInPath::No, false) => (self.ident.span, format!("{new_lifetime}")), + (Hidden, source) => { + unreachable!("can't suggest for a hidden lifetime of {source:?}") + } } } } @@ -398,7 +473,12 @@ pub struct InferArg { impl InferArg { pub fn to_ty(&self) -> Ty<'static> { - Ty { kind: TyKind::Infer(()), span: self.span, hir_id: self.hir_id } + Ty { + kind: TyKind::Infer(()), + span: self.span, + hir_id: self.hir_id, + source: TySource::Other, + } } } @@ -3151,6 +3231,16 @@ impl<'hir> AssocItemConstraintKind<'hir> { } } +#[derive(Debug, Clone, Copy, PartialEq, HashStable_Generic)] +pub enum TySource { + /// `Vec` in `Vec::new` + ImplicitSelf, + + /// Details not yet needed. Feel free to give useful + /// categorization to these usages. + Other, +} + /// An uninhabited enum used to make `Infer` variants on [`Ty`] and [`ConstArg`] be /// unreachable. Zero-Variant enums are guaranteed to have the same layout as the never /// type. @@ -3170,6 +3260,7 @@ pub struct Ty<'hir, Unambig = ()> { pub hir_id: HirId, pub span: Span, pub kind: TyKind<'hir, Unambig>, + pub source: TySource, } impl<'hir> Ty<'hir, AmbigArg> { @@ -4868,7 +4959,7 @@ mod size_asserts { static_assert_size!(StmtKind<'_>, 16); static_assert_size!(TraitItem<'_>, 88); static_assert_size!(TraitItemKind<'_>, 48); - static_assert_size!(Ty<'_>, 48); + static_assert_size!(Ty<'_>, 56); static_assert_size!(TyKind<'_>, 32); // tidy-alphabetical-end } diff --git a/compiler/rustc_hir/src/hir/tests.rs b/compiler/rustc_hir/src/hir/tests.rs index 62ef02d2f500c..256bfa1bba821 100644 --- a/compiler/rustc_hir/src/hir/tests.rs +++ b/compiler/rustc_hir/src/hir/tests.rs @@ -20,10 +20,10 @@ macro_rules! define_tests { define_tests! { cast_never TyKind Never {} - cast_tup TyKind Tup { 0: &[Ty { span: DUMMY_SP, hir_id: HirId::INVALID, kind: TyKind::Never }] } - cast_ptr TyKind Ptr { 0: MutTy { ty: &Ty { span: DUMMY_SP, hir_id: HirId::INVALID, kind: TyKind::Never }, mutbl: Mutability::Not }} + cast_tup TyKind Tup { 0: &[Ty { span: DUMMY_SP, hir_id: HirId::INVALID, kind: TyKind::Never, source: TySource::Other }] } + cast_ptr TyKind Ptr { 0: MutTy { ty: &Ty { span: DUMMY_SP, hir_id: HirId::INVALID, kind: TyKind::Never, source: TySource::Other }, mutbl: Mutability::Not }} cast_array TyKind Array { - 0: &Ty { span: DUMMY_SP, hir_id: HirId::INVALID, kind: TyKind::Never }, + 0: &Ty { span: DUMMY_SP, hir_id: HirId::INVALID, kind: TyKind::Never, source: TySource::Other }, 1: &ConstArg { hir_id: HirId::INVALID, kind: ConstArgKind::Anon(&AnonConst { hir_id: HirId::INVALID, def_id: LocalDefId { local_def_index: DefIndex::ZERO }, @@ -58,7 +58,8 @@ fn trait_object_roundtrips_impl(syntax: TraitObjectSyntax) { hir_id: HirId::INVALID, ident: Ident::new(sym::name, DUMMY_SP), res: LifetimeName::Static, - is_anon_in_path: IsAnonInPath::No, + source: LifetimeSource::Other, + syntax: LifetimeSyntax::Hidden, } }, syntax, diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index b73cd26927a5c..f8f52ef7349fc 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -5,7 +5,7 @@ use std::borrow::Cow; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagSymbolList, EmissionGuarantee, IntoDiagArg, MultiSpan, - SubdiagMessageOp, Subdiagnostic, + Subdiagnostic, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{self, Ty}; @@ -270,11 +270,7 @@ pub(crate) struct SuggestAnnotations { pub suggestions: Vec, } impl Subdiagnostic for SuggestAnnotations { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { if self.suggestions.is_empty() { return; } @@ -337,11 +333,7 @@ pub(crate) struct TypeMismatchFruTypo { } impl Subdiagnostic for TypeMismatchFruTypo { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("expr", self.expr.as_deref().unwrap_or("NONE")); // Only explain that `a ..b` is a range if it's split up @@ -599,11 +591,7 @@ pub(crate) struct RemoveSemiForCoerce { } impl Subdiagnostic for RemoveSemiForCoerce { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut multispan: MultiSpan = self.semi.into(); multispan.push_span_label(self.expr, fluent::hir_typeck_remove_semi_for_coerce_expr); multispan.push_span_label(self.ret, fluent::hir_typeck_remove_semi_for_coerce_ret); @@ -778,20 +766,16 @@ pub(crate) enum CastUnknownPointerSub { } impl rustc_errors::Subdiagnostic for CastUnknownPointerSub { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { CastUnknownPointerSub::To(span) => { - let msg = f(diag, crate::fluent_generated::hir_typeck_label_to); + let msg = diag.eagerly_translate(fluent::hir_typeck_label_to); diag.span_label(span, msg); - let msg = f(diag, crate::fluent_generated::hir_typeck_note); + let msg = diag.eagerly_translate(fluent::hir_typeck_note); diag.note(msg); } CastUnknownPointerSub::From(span) => { - let msg = f(diag, crate::fluent_generated::hir_typeck_label_from); + let msg = diag.eagerly_translate(fluent::hir_typeck_label_from); diag.span_label(span, msg); } } diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 782d328a95102..4d7e25f855896 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -251,11 +251,6 @@ lint_duplicate_macro_attribute = lint_duplicate_matcher_binding = duplicate matcher binding -lint_elided_named_lifetime = elided lifetime has a name - .label_elided = this elided lifetime gets resolved as `{$name}` - .label_named = lifetime `{$name}` declared here - .suggestion = consider specifying it explicitly - lint_enum_intrinsics_mem_discriminant = the return value of `mem::discriminant` is unspecified when called with a non-enum type .note = the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `{$ty_param}`, which is not an enum @@ -292,7 +287,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 -> @@ -508,6 +507,25 @@ lint_metavariable_still_repeating = variable `{$name}` is still repeating at thi lint_metavariable_wrong_operator = meta-variable repeats with different Kleene operator +lint_mismatched_lifetime_syntaxes = + lifetime flowing from input to output with different syntax + .label_mismatched_lifetime_syntaxes_inputs = + {$n_inputs -> + [one] this lifetime flows + *[other] these lifetimes flow + } to the output + .label_mismatched_lifetime_syntaxes_outputs = + the elided {$n_outputs -> + [one] lifetime gets + *[other] lifetimes get + } resolved as `{$lifetime_name}` + +lint_mismatched_lifetime_syntaxes_suggestion_hidden = + one option is to consistently hide the lifetime + +lint_mismatched_lifetime_syntaxes_suggestion_named = + one option is to consistently use `{$lifetime_name}` + lint_missing_fragment_specifier = missing fragment specifier lint_missing_unsafe_on_extern = extern blocks should be unsafe diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 885a7308bdc6d..9a67364b91df7 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 40ca9e05d95d6..b685f41fde748 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -4,17 +4,15 @@ 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; -use rustc_session::lint::{BuiltinLintDiag, ElidedLifetimeResolution}; -use rustc_span::{BytePos, kw}; +use rustc_session::lint::BuiltinLintDiag; +use rustc_span::BytePos; use tracing::debug; -use crate::lints::{self, ElidedNamedLifetime}; +use crate::lints; mod check_cfg; @@ -75,19 +73,6 @@ pub(super) fn decorate_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); @@ -450,16 +435,5 @@ pub(super) fn decorate_lint( BuiltinLintDiag::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by } => { lints::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by }.decorate_lint(diag) } - BuiltinLintDiag::ElidedNamedLifetimes { elided: (span, kind), resolution } => { - match resolution { - ElidedLifetimeResolution::Static => { - ElidedNamedLifetime { span, kind, name: kw::StaticLifetime, declaration: None } - } - ElidedLifetimeResolution::Param(name, declaration) => { - ElidedNamedLifetime { span, kind, name, declaration: Some(declaration) } - } - } - .decorate_lint(diag) - } } } diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs index d109a5c90305e..586e55c8055c9 100644 --- a/compiler/rustc_lint/src/errors.rs +++ b/compiler/rustc_lint/src/errors.rs @@ -1,5 +1,5 @@ use rustc_errors::codes::*; -use rustc_errors::{Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic}; +use rustc_errors::{Diag, EmissionGuarantee, Subdiagnostic}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_session::lint::Level; use rustc_span::{Span, Symbol}; @@ -26,11 +26,7 @@ pub(crate) enum OverruledAttributeSub { } impl Subdiagnostic for OverruledAttributeSub { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { OverruledAttributeSub::DefaultSource { id } => { diag.note(fluent::lint_default_source); diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs index 39ea8d8e3246c..a9b04511c6b47 100644 --- a/compiler/rustc_lint/src/if_let_rescope.rs +++ b/compiler/rustc_lint/src/if_let_rescope.rs @@ -3,9 +3,7 @@ use std::ops::ControlFlow; use hir::intravisit::{self, Visitor}; use rustc_ast::Recovered; -use rustc_errors::{ - Applicability, Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic, SuggestionStyle, -}; +use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic, SuggestionStyle}; use rustc_hir::{self as hir, HirIdSet}; use rustc_macros::{LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::adjustment::Adjust; @@ -327,11 +325,7 @@ struct IfLetRescopeRewrite { } impl Subdiagnostic for IfLetRescopeRewrite { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut suggestions = vec![]; for match_head in self.match_heads { match match_head { @@ -360,7 +354,7 @@ impl Subdiagnostic for IfLetRescopeRewrite { .chain(repeat('}').take(closing_brackets.count)) .collect(), )); - let msg = f(diag, crate::fluent_generated::lint_suggestion); + let msg = diag.eagerly_translate(crate::fluent_generated::lint_suggestion); diag.multipart_suggestion_with_style( msg, suggestions, diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 9b5c564d3324b..11beba02a281c 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -57,6 +57,7 @@ mod invalid_from_utf8; mod late; mod let_underscore; mod levels; +mod lifetime_style; mod lints; mod macro_expr_fragment_specifier_2024_migration; mod map_unit_fn; @@ -97,6 +98,7 @@ use impl_trait_overcaptures::ImplTraitOvercaptures; use internal::*; use invalid_from_utf8::*; use let_underscore::*; +use lifetime_style::*; use macro_expr_fragment_specifier_2024_migration::*; use map_unit_fn::*; use multiple_supertrait_upcastable::*; @@ -246,6 +248,8 @@ late_lint_methods!( IfLetRescope: IfLetRescope::default(), StaticMutRefs: StaticMutRefs, UnqualifiedLocalImports: UnqualifiedLocalImports, + LifetimeStyle: LifetimeStyle, + HiddenLifetimesInTypePaths: HiddenLifetimesInTypePaths::default(), ] ] ); @@ -266,7 +270,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)),*]); ) } @@ -281,7 +285,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!( @@ -307,7 +311,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); @@ -317,14 +321,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); @@ -337,9 +343,15 @@ fn register_builtins(store: &mut LintStore) { add_lint_group!("deprecated_safe", DEPRECATED_SAFE_2024); + 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"); @@ -353,6 +365,11 @@ fn register_builtins(store: &mut LintStore) { store.register_renamed("unused_tuple_struct_fields", "dead_code"); store.register_renamed("static_mut_ref", "static_mut_refs"); 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 diff --git a/compiler/rustc_lint/src/lifetime_style.rs b/compiler/rustc_lint/src/lifetime_style.rs new file mode 100644 index 0000000000000..04396016fa292 --- /dev/null +++ b/compiler/rustc_lint/src/lifetime_style.rs @@ -0,0 +1,536 @@ +use std::slice; + +use rustc_data_structures::fx::FxIndexMap; +use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::{self as hir, LifetimeSource, LifetimeSyntax}; +use rustc_session::lint::Lint; +use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass}; +use rustc_span::Span; +use tracing::instrument; + +use crate::{LateContext, LateLintPass, LintContext, lints}; + +declare_lint! { + /// The `mismatched_lifetime_syntaxes` lint detects when an + /// elided lifetime uses different syntax between function + /// arguments and return values. + /// + /// The three kinds of syntax are: + /// 1. Named lifetimes, such as `'static` or `'a`. + /// 2. The anonymous lifetime `'_`. + /// 3. Hidden lifetimes, such as `&u8` or `ThisHasALifetimeGeneric`. + /// + /// As an exception, this lint allows references with hidden or + /// anonymous lifetimes to be paired with paths using anonymous + /// lifetimes. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(mismatched_lifetime_syntaxes)] + /// + /// pub fn mixing_named_with_hidden(v: &'static u8) -> &u8 { + /// v + /// } + /// + /// struct Person<'a> { + /// name: &'a str, + /// } + /// + /// pub fn mixing_hidden_with_anonymous(v: Person) -> Person<'_> { + /// v + /// } + /// + /// struct Foo; + /// + /// impl Foo { + /// // Lifetime elision results in the output lifetime becoming + /// // `'static`, which is not what was intended. + /// pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 { + /// unsafe { &mut *(x as *mut _) } + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Lifetime elision is useful because it frees you from having to + /// give each lifetime its own name and explicitly show the + /// relation of input and output lifetimes for common + /// cases. However, a lifetime that uses inconsistent syntax + /// between related arguments and return values is more confusing. + /// + /// In certain `unsafe` code, lifetime elision combined with + /// inconsistent lifetime syntax may result in unsound code. + pub MISMATCHED_LIFETIME_SYNTAXES, + Warn, + "detects when an elided lifetime uses different syntax between arguments and return values" +} + +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!(LifetimeStyle => [ + MISMATCHED_LIFETIME_SYNTAXES, + HIDDEN_LIFETIMES_IN_INPUT_PATHS, + HIDDEN_LIFETIMES_IN_OUTPUT_PATHS, +]); + +impl<'tcx> LateLintPass<'tcx> for LifetimeStyle { + #[instrument(skip_all)] + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + _: hir::intravisit::FnKind<'tcx>, + fd: &'tcx hir::FnDecl<'tcx>, + _: &'tcx hir::Body<'tcx>, + _: rustc_span::Span, + _: rustc_span::def_id::LocalDefId, + ) { + let mut input_map = Default::default(); + let mut output_map = Default::default(); + + for input in fd.inputs { + LifetimeInfoCollector::collect(input, &mut input_map); + } + + if let hir::FnRetTy::Return(output) = fd.output { + LifetimeInfoCollector::collect(output, &mut output_map); + } + + 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)] +fn report_mismatches<'tcx>( + cx: &LateContext<'tcx>, + inputs: &LifetimeInfoMap<'tcx>, + outputs: &LifetimeInfoMap<'tcx>, +) { + for (resolved_lifetime, output_info) in outputs { + if let Some(input_info) = inputs.get(resolved_lifetime) { + let relevant_lifetimes = input_info.iter().chain(output_info); + + // Categorize lifetimes into source/syntax buckets + let mut hidden = Bucket::default(); + let mut anonymous = Bucket::default(); + let mut named = Bucket::default(); + + for info in relevant_lifetimes { + use LifetimeSource::*; + use LifetimeSyntax::*; + + let bucket = match info.lifetime.syntax { + Hidden => &mut hidden, + Anonymous => &mut anonymous, + Named => &mut named, + }; + + match info.lifetime.source { + Reference | OutlivesBound | PreciseCapturing => bucket.n_ref += 1, + Path { .. } => bucket.n_path += 1, + Other => {} + } + + bucket.members.push(info); + } + + // Check if syntaxes are consistent + + let syntax_counts = ( + hidden.n_ref, + anonymous.n_ref, + named.n_ref, + hidden.n_path, + anonymous.n_path, + named.n_path, + ); + + match syntax_counts { + // The lifetimes are all one syntax + (_, 0, 0, _, 0, 0) | (0, _, 0, 0, _, 0) | (0, 0, _, 0, 0, _) => continue, + + // Hidden references, anonymous references, and anonymous paths can call be mixed. + (_, _, 0, 0, _, 0) => continue, + + _ => (), + } + + let inputs = input_info.iter().map(|info| info.reporting_span()).collect(); + let outputs = output_info.iter().map(|info| info.reporting_span()).collect(); + + // There can only ever be zero or one named lifetime + // for a given lifetime resolution. + let named_lifetime = named.members.first(); + + let named_suggestion = named_lifetime.map(|info| { + build_mismatch_suggestion(info.lifetime_name(), &[&hidden, &anonymous]) + }); + + let is_named_static = named_lifetime.is_some_and(|info| info.is_static()); + + let should_suggest_hidden = !hidden.members.is_empty() && !is_named_static; + + // FIXME: remove comma and space from paths with multiple generics + // FIXME: remove angle brackets from paths when no more generics + // FIXME: remove space after lifetime from references + // FIXME: remove lifetime from function declaration + let hidden_suggestion = should_suggest_hidden.then(|| { + let suggestions = [&anonymous, &named] + .into_iter() + .flat_map(|b| &b.members) + .map(|i| i.suggestion("'dummy").0) + .collect(); + + lints::MismatchedLifetimeSyntaxesSuggestion::Hidden { + suggestions, + tool_only: false, + } + }); + + let should_suggest_anonymous = !anonymous.members.is_empty() && !is_named_static; + + let anonymous_suggestion = should_suggest_anonymous + .then(|| build_mismatch_suggestion("'_", &[&hidden, &named])); + + let lifetime_name = + named_lifetime.map(|info| info.lifetime_name()).unwrap_or("'_").to_owned(); + + // We can produce a number of suggestions which may overwhelm + // the user. Instead, we order the suggestions based on Rust + // idioms. The "best" choice is shown to the user and the + // remaining choices are shown to tools only. + let mut suggestions = Vec::new(); + suggestions.extend(named_suggestion); + suggestions.extend(anonymous_suggestion); + suggestions.extend(hidden_suggestion); + + cx.emit_span_lint( + MISMATCHED_LIFETIME_SYNTAXES, + Vec::clone(&inputs), + lints::MismatchedLifetimeSyntaxes { lifetime_name, inputs, outputs, suggestions }, + ); + } + } +} + +#[derive(Default)] +struct Bucket<'a, 'tcx> { + members: Vec<&'a Info<'tcx>>, + n_ref: usize, + n_path: usize, +} + +fn build_mismatch_suggestion( + lifetime_name: &str, + buckets: &[&Bucket<'_, '_>], +) -> lints::MismatchedLifetimeSyntaxesSuggestion { + let lifetime_name = lifetime_name.to_owned(); + + let suggestions = buckets + .iter() + .flat_map(|b| &b.members) + .map(|info| info.suggestion(&lifetime_name)) + .collect(); + + lints::MismatchedLifetimeSyntaxesSuggestion::Named { + lifetime_name, + suggestions, + tool_only: false, + } +} + +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_syntactically_hidden() + }); + + 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(res: hir::LifetimeName) -> bool { + matches!( + res, + hir::LifetimeName::Param(..) | hir::LifetimeName::Infer | hir::LifetimeName::Static + ) +} + +struct Info<'tcx> { + type_span: Span, + lifetime: &'tcx hir::Lifetime, +} + +impl<'tcx> Info<'tcx> { + fn lifetime_name(&self) -> &str { + self.lifetime.ident.as_str() + } + + fn is_static(&self) -> bool { + self.lifetime.is_static() + } + + /// When reporting a lifetime that is hidden, we expand the span + /// to include the type. Otherwise we end up pointing at nothing, + /// which is a bit confusing. + fn reporting_span(&self) -> Span { + if self.lifetime.is_syntactically_hidden() { + self.type_span + } else { + self.lifetime.ident.span + } + } + + fn suggestion(&self, lifetime_name: &str) -> (Span, String) { + self.lifetime.suggestion(lifetime_name) + } +} + +type LifetimeInfoMap<'tcx> = FxIndexMap<&'tcx hir::LifetimeName, Vec>>; + +struct LifetimeInfoCollector<'a, 'tcx> { + type_span: Span, + map: &'a mut LifetimeInfoMap<'tcx>, +} + +impl<'a, 'tcx> LifetimeInfoCollector<'a, 'tcx> { + fn collect(ty: &'tcx hir::Ty<'tcx>, map: &'a mut LifetimeInfoMap<'tcx>) { + let mut this = Self { type_span: ty.span, map }; + + intravisit::walk_unambig_ty(&mut this, ty); + } +} + +impl<'a, 'tcx> Visitor<'tcx> for LifetimeInfoCollector<'a, 'tcx> { + #[instrument(skip(self))] + fn visit_lifetime(&mut self, lifetime: &'tcx hir::Lifetime) { + let type_span = self.type_span; + + let info = Info { type_span, lifetime }; + + self.map.entry(&lifetime.res).or_default().push(info); + } + + #[instrument(skip(self))] + fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, hir::AmbigArg>) -> Self::Result { + let old_type_span = self.type_span; + + self.type_span = ty.span; + + intravisit::walk_ty(self, ty); + + self.type_span = old_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]); + +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; + } + + // Do not lint about usages like `ContainsLifetime::method` or + // `ContainsLifetimeAndType::::method`. + if ty.source == hir::TySource::ImplicitSelf { + 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_syntactically_hidden() + && reportable_lifetime_resolution(lifetime.res) + { + 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 55d010e6d34aa..ce64386f8ad9b 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -5,20 +5,20 @@ use std::num::NonZero; use rustc_abi::ExternAbi; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString, ElidedLifetimeInPathSubdiag, - EmissionGuarantee, LintDiagnostic, MultiSpan, SubdiagMessageOp, Subdiagnostic, SuggestionStyle, + Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString, EmissionGuarantee, + LintDiagnostic, MultiSpan, Subdiagnostic, SuggestionStyle, }; +use rustc_hir as hir; use rustc_hir::def::Namespace; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::VisitorExt; -use rustc_hir::{self as hir, MissingLifetimeKind}; use rustc_macros::{LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::inhabitedness::InhabitedPredicate; use rustc_middle::ty::{Clause, PolyExistentialTraitRef, Ty, TyCtxt}; use rustc_session::Session; use rustc_session::lint::AmbiguityErrorDiag; use rustc_span::edition::Edition; -use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol, kw, sym}; +use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol, sym}; use crate::builtin::{InitError, ShorthandAssocTyCollector, TypeAliasBounds}; use crate::errors::{OverruledAttributeSub, RequestedLevel}; @@ -449,11 +449,7 @@ pub(crate) struct BuiltinUnpermittedTypeInitSub { } impl Subdiagnostic for BuiltinUnpermittedTypeInitSub { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut err = self.err; loop { if let Some(span) = err.span { @@ -504,11 +500,7 @@ pub(crate) struct BuiltinClashingExternSub<'a> { } impl Subdiagnostic for BuiltinClashingExternSub<'_> { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut expected_str = DiagStyledString::new(); expected_str.push(self.expected.fn_sig(self.tcx).to_string(), false); let mut found_str = DiagStyledString::new(); @@ -824,11 +816,7 @@ pub(crate) struct HiddenUnicodeCodepointsDiagLabels { } impl Subdiagnostic for HiddenUnicodeCodepointsDiagLabels { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { for (c, span) in self.spans { diag.span_label(span, format!("{c:?}")); } @@ -842,11 +830,7 @@ pub(crate) enum HiddenUnicodeCodepointsDiagSub { // Used because of multiple multipart_suggestion and note impl Subdiagnostic for HiddenUnicodeCodepointsDiagSub { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { HiddenUnicodeCodepointsDiagSub::Escape { spans } => { diag.multipart_suggestion_with_style( @@ -1015,11 +999,7 @@ pub(crate) struct NonBindingLetSub { } impl Subdiagnostic for NonBindingLetSub { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let can_suggest_binding = self.drop_fn_start_end.is_some() || !self.is_assign_desugar; if can_suggest_binding { @@ -1303,11 +1283,7 @@ pub(crate) enum NonSnakeCaseDiagSub { } impl Subdiagnostic for NonSnakeCaseDiagSub { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { NonSnakeCaseDiagSub::Label { span } => { diag.span_label(span, fluent::lint_label); @@ -1629,11 +1605,7 @@ pub(crate) enum OverflowingBinHexSign { } impl Subdiagnostic for OverflowingBinHexSign { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { OverflowingBinHexSign::Positive => { diag.note(fluent::lint_positive_note); @@ -2690,65 +2662,6 @@ pub(crate) struct MacroExpandedMacroExportsAccessedByAbsolutePaths { pub definition: Span, } -#[derive(LintDiagnostic)] -#[diag(lint_hidden_lifetime_parameters)] -pub(crate) struct ElidedLifetimesInPaths { - #[subdiagnostic] - pub subdiag: ElidedLifetimeInPathSubdiag, -} - -pub(crate) struct ElidedNamedLifetime { - pub span: Span, - pub kind: MissingLifetimeKind, - pub name: Symbol, - pub declaration: Option, -} - -impl LintDiagnostic<'_, G> for ElidedNamedLifetime { - fn decorate_lint(self, diag: &mut rustc_errors::Diag<'_, G>) { - let Self { span, kind, name, declaration } = self; - diag.primary_message(fluent::lint_elided_named_lifetime); - diag.arg("name", name); - diag.span_label(span, fluent::lint_label_elided); - if let Some(declaration) = declaration { - diag.span_label(declaration, fluent::lint_label_named); - } - // FIXME(GrigorenkoPV): this `if` and `return` should be removed, - // but currently this lint's suggestions can conflict with those of `clippy::needless_lifetimes`: - // https://github.com/rust-lang/rust/pull/129840#issuecomment-2323349119 - // HACK: `'static` suggestions will never sonflict, emit only those for now. - if name != kw::StaticLifetime { - return; - } - match kind { - MissingLifetimeKind::Underscore => diag.span_suggestion_verbose( - span, - fluent::lint_suggestion, - format!("{name}"), - Applicability::MachineApplicable, - ), - MissingLifetimeKind::Ampersand => diag.span_suggestion_verbose( - span.shrink_to_hi(), - fluent::lint_suggestion, - format!("{name} "), - Applicability::MachineApplicable, - ), - MissingLifetimeKind::Comma => diag.span_suggestion_verbose( - span.shrink_to_hi(), - fluent::lint_suggestion, - format!("{name}, "), - Applicability::MachineApplicable, - ), - MissingLifetimeKind::Brackets => diag.span_suggestion_verbose( - span.shrink_to_hi(), - fluent::lint_suggestion, - format!("<{name}>"), - Applicability::MachineApplicable, - ), - }; - } -} - #[derive(LintDiagnostic)] #[diag(lint_invalid_crate_type_value)] pub(crate) struct UnknownCrateTypes { @@ -3184,3 +3097,116 @@ pub(crate) struct ReservedMultihash { #[suggestion(code = " ", applicability = "machine-applicable")] pub suggestion: Span, } + +pub(crate) struct MismatchedLifetimeSyntaxes { + pub lifetime_name: String, + pub inputs: Vec, + pub outputs: Vec, + + pub suggestions: Vec, +} + +impl<'a, G: EmissionGuarantee> LintDiagnostic<'a, G> for MismatchedLifetimeSyntaxes { + fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>) { + diag.primary_message(fluent::lint_mismatched_lifetime_syntaxes); + + diag.arg("lifetime_name", self.lifetime_name); + + diag.arg("n_inputs", self.inputs.len()); + for input in self.inputs { + let a = diag.eagerly_translate(fluent::lint_label_mismatched_lifetime_syntaxes_inputs); + diag.span_label(input, a); + } + + diag.arg("n_outputs", self.outputs.len()); + for output in self.outputs { + let a = diag.eagerly_translate(fluent::lint_label_mismatched_lifetime_syntaxes_outputs); + diag.span_label(output, a); + } + + let mut suggestions = self.suggestions.into_iter(); + if let Some(s) = suggestions.next() { + diag.subdiagnostic(s); + + for mut s in suggestions { + s.make_tool_only(); + diag.subdiagnostic(s); + } + } + } +} + +pub(crate) enum MismatchedLifetimeSyntaxesSuggestion { + Hidden { suggestions: Vec, tool_only: bool }, + + Named { lifetime_name: String, suggestions: Vec<(Span, String)>, tool_only: bool }, +} + +impl MismatchedLifetimeSyntaxesSuggestion { + fn make_tool_only(&mut self) { + use MismatchedLifetimeSyntaxesSuggestion::*; + + let tool_only = match self { + Hidden { tool_only, .. } | Named { tool_only, .. } => tool_only, + }; + + *tool_only = true; + } +} + +impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { + use MismatchedLifetimeSyntaxesSuggestion::*; + + let style = |tool_only| { + if tool_only { SuggestionStyle::CompletelyHidden } else { SuggestionStyle::ShowAlways } + }; + + match self { + Hidden { suggestions, tool_only } => { + let suggestions = suggestions.into_iter().map(|s| (s, String::new())).collect(); + diag.multipart_suggestion_with_style( + fluent::lint_mismatched_lifetime_syntaxes_suggestion_hidden, + suggestions, + Applicability::MachineApplicable, + style(tool_only), + ); + } + + Named { lifetime_name, suggestions, tool_only } => { + diag.arg("lifetime_name", lifetime_name); + + let msg = diag + .eagerly_translate(fluent::lint_mismatched_lifetime_syntaxes_suggestion_named); + + diag.multipart_suggestion_with_style( + msg, + suggestions, + Applicability::MachineApplicable, + style(tool_only), + ); + } + } + } +} + +#[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 8a761a0a0969b..3bea5e2d0eedf 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -39,8 +39,6 @@ declare_lint_pass! { DEPRECATED_WHERE_CLAUSE_LOCATION, DUPLICATE_MACRO_ATTRIBUTES, ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT, - ELIDED_LIFETIMES_IN_PATHS, - ELIDED_NAMED_LIFETIMES, EXPLICIT_BUILTIN_CFGS_IN_FLAGS, EXPORTED_PRIVATE_DEPENDENCIES, FFI_UNWIND_CALLS, @@ -1793,73 +1791,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 `elided_named_lifetimes` lint detects when an elided - /// lifetime ends up being a named lifetime, such as `'static` - /// or some lifetime parameter `'a`. - /// - /// ### Example - /// - /// ```rust,compile_fail - /// #![deny(elided_named_lifetimes)] - /// struct Foo; - /// impl Foo { - /// pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 { - /// unsafe { &mut *(x as *mut _) } - /// } - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// Lifetime elision is quite useful, because it frees you from having - /// to give each lifetime its own name, but sometimes it can produce - /// somewhat surprising resolutions. In safe code, it is mostly okay, - /// because the borrow checker prevents any unsoundness, so the worst - /// case scenario is you get a confusing error message in some other place. - /// But with `unsafe` code, such unexpected resolutions may lead to unsound code. - pub ELIDED_NAMED_LIFETIMES, - Warn, - "detects when an elided lifetime gets resolved to be `'static` or some named parameter" -} - 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 7fdbae3a59d7e..c84ddccc9d1de 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -9,7 +9,7 @@ use rustc_data_structures::stable_hasher::{ use rustc_error_messages::{DiagMessage, MultiSpan}; use rustc_hir::def::Namespace; use rustc_hir::def_id::DefPathHash; -use rustc_hir::{HashStableContext, HirId, ItemLocalId, MissingLifetimeKind}; +use rustc_hir::{HashStableContext, HirId, ItemLocalId}; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; pub use rustc_span::edition::Edition; use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol, sym}; @@ -635,12 +635,6 @@ pub enum DeprecatedSinceKind { InVersion(String), } -#[derive(Debug)] -pub enum ElidedLifetimeResolution { - Static, - Param(Symbol, Span), -} - // This could be a closure, but then implementing derive trait // becomes hacky (and it gets allocated). #[derive(Debug)] @@ -652,11 +646,6 @@ pub enum BuiltinLintDiag { ident: Ident, }, MacroExpandedMacroExportsAccessedByAbsolutePaths(Span), - ElidedLifetimesInPaths(usize, Span, bool, Span), - ElidedNamedLifetimes { - elided: (Span, MissingLifetimeKind), - resolution: ElidedLifetimeResolution, - }, UnknownCrateTypes { span: Span, candidate: Option, diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index 909083d5e8652..bc9516b2e0c67 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -20,14 +20,12 @@ use crate::diagnostics::utils::{ /// The central struct for constructing the `add_to_diag` method from an annotated struct. pub(crate) struct SubdiagnosticDerive { diag: syn::Ident, - f: syn::Ident, } impl SubdiagnosticDerive { pub(crate) fn new() -> Self { let diag = format_ident!("diag"); - let f = format_ident!("f"); - Self { diag, f } + Self { diag } } pub(crate) fn into_tokens(self, mut structure: Structure<'_>) -> TokenStream { @@ -86,19 +84,16 @@ impl SubdiagnosticDerive { }; let diag = &self.diag; - let f = &self.f; // FIXME(edition_2024): Fix the `keyword_idents_2024` lint to not trigger here? #[allow(keyword_idents_2024)] let ret = structure.gen_impl(quote! { gen impl rustc_errors::Subdiagnostic for @Self { - fn add_to_diag_with<__G, __F>( + fn add_to_diag<__G>( self, #diag: &mut rustc_errors::Diag<'_, __G>, - #f: &__F ) where __G: rustc_errors::EmissionGuarantee, - __F: rustc_errors::SubdiagMessageOp<__G>, { #implementation } @@ -384,11 +379,10 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { Ok(quote! {}) } "subdiagnostic" => { - let f = &self.parent.f; let diag = &self.parent.diag; let binding = &info.binding; self.has_subdiagnostic = true; - Ok(quote! { #binding.add_to_diag_with(#diag, #f); }) + Ok(quote! { #binding.add_to_diag(#diag); }) } _ => { let mut span_attrs = vec![]; @@ -531,12 +525,11 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { let span_field = self.span_field.value_ref(); let diag = &self.parent.diag; - let f = &self.parent.f; let mut calls = TokenStream::new(); for (kind, slug, no_span) in kind_slugs { let message = format_ident!("__message"); calls.extend( - quote! { let #message = #f(#diag, crate::fluent_generated::#slug.into()); }, + quote! { let #message = #diag.eagerly_translate(crate::fluent_generated::#slug); }, ); let name = format_ident!( diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 0e16f871b16f9..ae09db5023527 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, - MultiSpan, SubdiagMessageOp, Subdiagnostic, pluralize, + MultiSpan, Subdiagnostic, pluralize, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{self, Ty}; @@ -546,11 +546,7 @@ pub(crate) struct UnsafeNotInheritedLintNote { } impl Subdiagnostic for UnsafeNotInheritedLintNote { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.span_note(self.signature_span, fluent::mir_build_unsafe_fn_safe_body); let body_start = self.body_span.shrink_to_lo(); let body_end = self.body_span.shrink_to_hi(); @@ -1031,11 +1027,7 @@ pub(crate) struct Variant { } impl<'tcx> Subdiagnostic for AdtDefinedHere<'tcx> { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("ty", self.ty); let mut spans = MultiSpan::from(self.adt_def_span); @@ -1117,11 +1109,7 @@ pub(crate) struct Rust2024IncompatiblePatSugg { } impl Subdiagnostic for Rust2024IncompatiblePatSugg { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { // Format and emit explanatory notes about default binding modes. Reversing the spans' order // means if we have nested spans, the innermost ones will be visited first. for (span, def_br_mutbl) in self.default_mode_labels.into_iter().rev() { diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs index 29a9133abe93d..537f152938ef3 100644 --- a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs +++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs @@ -512,23 +512,17 @@ struct LocalLabel<'a> { /// A custom `Subdiagnostic` implementation so that the notes are delivered in a specific order impl Subdiagnostic for LocalLabel<'_> { - fn add_to_diag_with< - G: rustc_errors::EmissionGuarantee, - F: rustc_errors::SubdiagMessageOp, - >( - self, - diag: &mut rustc_errors::Diag<'_, G>, - f: &F, - ) { + fn add_to_diag(self, diag: &mut rustc_errors::Diag<'_, G>) { diag.arg("name", self.name); diag.arg("is_generated_name", self.is_generated_name); diag.arg("is_dropped_first_edition_2024", self.is_dropped_first_edition_2024); - let msg = f(diag, crate::fluent_generated::mir_transform_tail_expr_local.into()); + let msg = diag.eagerly_translate(crate::fluent_generated::mir_transform_tail_expr_local); diag.span_label(self.span, msg); for dtor in self.destructors { - dtor.add_to_diag_with(diag, f); + dtor.add_to_diag(diag); } - let msg = f(diag, crate::fluent_generated::mir_transform_label_local_epilogue); + let msg = + diag.eagerly_translate(crate::fluent_generated::mir_transform_label_local_epilogue); diag.span_label(self.span, msg); } } diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index dfdef018bc374..57534bc8c318d 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -7,8 +7,7 @@ use rustc_ast::util::parser::ExprPrecedence; use rustc_ast::{Path, Visibility}; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, SubdiagMessageOp, - Subdiagnostic, + Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, Subdiagnostic, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_session::errors::ExprParenthesesNeeded; @@ -1551,11 +1550,7 @@ pub(crate) struct FnTraitMissingParen { } impl Subdiagnostic for FnTraitMissingParen { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.span_label(self.span, crate::fluent_generated::parse_fn_trait_missing_paren); diag.span_suggestion_short( self.span.shrink_to_hi(), diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 4e3e0324205a4..093069deeca86 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -5,7 +5,7 @@ use rustc_ast::Label; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level, - MultiSpan, SubdiagMessageOp, Subdiagnostic, + MultiSpan, Subdiagnostic, }; use rustc_hir::{self as hir, ExprKind, Target}; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; @@ -1856,11 +1856,7 @@ pub(crate) struct UnusedVariableStringInterp { } impl Subdiagnostic for UnusedVariableStringInterp { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.span_label(self.lit, crate::fluent_generated::passes_maybe_string_interpolation); diag.multipart_suggestion( crate::fluent_generated::passes_string_interpolation_only_works, diff --git a/compiler/rustc_pattern_analysis/src/errors.rs b/compiler/rustc_pattern_analysis/src/errors.rs index 1f7852e5190d2..e60930d6cd21c 100644 --- a/compiler/rustc_pattern_analysis/src/errors.rs +++ b/compiler/rustc_pattern_analysis/src/errors.rs @@ -1,4 +1,4 @@ -use rustc_errors::{Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic}; +use rustc_errors::{Diag, EmissionGuarantee, Subdiagnostic}; use rustc_macros::{LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; use rustc_span::Span; @@ -55,11 +55,7 @@ pub struct Overlap { } impl Subdiagnostic for Overlap { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let Overlap { span, range } = self; // FIXME(mejrs) unfortunately `#[derive(LintDiagnostic)]` @@ -103,11 +99,7 @@ pub struct GappedRange { } impl Subdiagnostic for GappedRange { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let GappedRange { span, gap, first_range } = self; // FIXME(mejrs) unfortunately `#[derive(LintDiagnostic)]` diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 1389e8c811eb3..bf8602e4601e1 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1701,7 +1701,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { if ident.name == kw::StaticLifetime { self.record_lifetime_res( lifetime.id, - LifetimeRes::Static { suppress_elision_warning: false }, + LifetimeRes::Static, LifetimeElisionCandidate::Named, ); return; @@ -1849,8 +1849,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { if lifetimes_in_scope.is_empty() { self.record_lifetime_res( lifetime.id, - // We are inside a const item, so do not warn. - LifetimeRes::Static { suppress_elision_warning: true }, + LifetimeRes::Static, elision_candidate, ); return; @@ -2077,7 +2076,6 @@ impl<'a, 'ast, 'ra: 'ast, '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 @@ -2100,7 +2098,6 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { span: path_span, subdiag, }); - should_lint = false; for id in node_ids { self.record_lifetime_res( @@ -2169,20 +2166,6 @@ impl<'a, 'ast, 'ra: 'ast, '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, - ), - ); - } } } @@ -2197,47 +2180,6 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { panic!("lifetime {id:?} resolved multiple times ({prev_res:?} before, {res:?} now)") } - match candidate { - LifetimeElisionCandidate::Missing(missing @ MissingLifetime { .. }) => { - debug_assert_eq!(id, missing.id); - match res { - LifetimeRes::Static { suppress_elision_warning } => { - if !suppress_elision_warning { - self.r.lint_buffer.buffer_lint( - lint::builtin::ELIDED_NAMED_LIFETIMES, - missing.id_for_lint, - missing.span, - BuiltinLintDiag::ElidedNamedLifetimes { - elided: (missing.span, missing.kind), - resolution: lint::ElidedLifetimeResolution::Static, - }, - ); - } - } - LifetimeRes::Param { param, binder: _ } => { - let tcx = self.r.tcx(); - self.r.lint_buffer.buffer_lint( - lint::builtin::ELIDED_NAMED_LIFETIMES, - missing.id_for_lint, - missing.span, - BuiltinLintDiag::ElidedNamedLifetimes { - elided: (missing.span, missing.kind), - resolution: lint::ElidedLifetimeResolution::Param( - tcx.item_name(param.into()), - tcx.source_span(param), - ), - }, - ); - } - LifetimeRes::Fresh { .. } - | LifetimeRes::Infer - | LifetimeRes::Error - | LifetimeRes::ElidedAnchor { .. } => {} - } - } - LifetimeElisionCandidate::Ignore | LifetimeElisionCandidate::Named => {} - } - match res { LifetimeRes::Param { .. } | LifetimeRes::Fresh { .. } | LifetimeRes::Static { .. } => { if let Some(ref mut candidates) = self.lifetime_elision_candidates { @@ -2755,14 +2697,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { .. }) => { self.with_static_rib(def_kind, |this| { - this.with_lifetime_rib( - LifetimeRibKind::Elided(LifetimeRes::Static { - suppress_elision_warning: true, - }), - |this| { - this.visit_ty(ty); - }, - ); + this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| { + this.visit_ty(ty); + }); if let Some(expr) = expr { // We already forbid generic params because of the above item rib, // so it doesn't matter whether this is a trivial constant. @@ -2799,9 +2736,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { this.visit_generics(generics); this.with_lifetime_rib( - LifetimeRibKind::Elided(LifetimeRes::Static { - suppress_elision_warning: true, - }), + LifetimeRibKind::Elided(LifetimeRes::Static), |this| this.visit_ty(ty), ); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index b62bc6c45e0c5..a301eb2ed60cf 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -3275,7 +3275,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { maybe_static = true; in_scope_lifetimes = vec![( Ident::with_dummy_span(kw::StaticLifetime), - (DUMMY_NODE_ID, LifetimeRes::Static { suppress_elision_warning: false }), + (DUMMY_NODE_ID, LifetimeRes::Static), )]; } } else if elided_len == 0 { @@ -3287,7 +3287,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { maybe_static = true; in_scope_lifetimes = vec![( Ident::with_dummy_span(kw::StaticLifetime), - (DUMMY_NODE_ID, LifetimeRes::Static { suppress_elision_warning: false }), + (DUMMY_NODE_ID, LifetimeRes::Static), )]; } } else if num_params == 1 { diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 9f7bfe5101ab2..ef953a6503af3 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -4,12 +4,12 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic, - EmissionGuarantee, IntoDiagArg, Level, MultiSpan, SubdiagMessageOp, Subdiagnostic, + EmissionGuarantee, IntoDiagArg, Level, MultiSpan, Subdiagnostic, }; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{Visitor, VisitorExt, walk_ty}; -use rustc_hir::{self as hir, AmbigArg, FnRetTy, GenericParamKind, IsAnonInPath, Node}; +use rustc_hir::{self as hir, AmbigArg, FnRetTy, GenericParamKind, Node}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::print::{PrintTraitRefExt as _, TraitRefPrintOnlyTraitPath}; use rustc_middle::ty::{self, Binder, ClosureKind, FnSig, GenericArg, Region, Ty, TyCtxt}; @@ -107,11 +107,7 @@ pub enum AdjustSignatureBorrow { } impl Subdiagnostic for AdjustSignatureBorrow { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { AdjustSignatureBorrow::Borrow { to_borrow } => { diag.arg("len", to_borrow.len()); @@ -381,11 +377,7 @@ pub enum RegionOriginNote<'a> { } impl Subdiagnostic for RegionOriginNote<'_> { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut label_or_note = |span, msg: DiagMessage| { let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count(); let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count(); @@ -446,11 +438,7 @@ pub enum LifetimeMismatchLabels { } impl Subdiagnostic for LifetimeMismatchLabels { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => { diag.span_label(param_span, fluent::trait_selection_declared_different); @@ -495,11 +483,7 @@ pub struct AddLifetimeParamsSuggestion<'a> { } impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut mk_suggestion = || { let Some(anon_reg) = self.tcx.is_suitable_region(self.generic_param_scope, self.sub) else { @@ -567,19 +551,6 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { impl<'v> Visitor<'v> for ImplicitLifetimeFinder { fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) { - let make_suggestion = |lifetime: &hir::Lifetime| { - if lifetime.is_anon_in_path == IsAnonInPath::Yes - && lifetime.ident.span.is_empty() - { - format!("{}, ", self.suggestion_param_name) - } else if lifetime.ident.name == kw::UnderscoreLifetime - && lifetime.ident.span.is_empty() - { - format!("{} ", self.suggestion_param_name) - } else { - self.suggestion_param_name.clone() - } - }; match ty.kind { hir::TyKind::Path(hir::QPath::Resolved(_, path)) => { for segment in path.segments { @@ -588,7 +559,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { matches!( arg, hir::GenericArg::Lifetime(lifetime) - if lifetime.is_anon_in_path == IsAnonInPath::Yes + if lifetime.is_syntactically_hidden() ) }) { self.suggestions.push(( @@ -607,10 +578,10 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { if let hir::GenericArg::Lifetime(lifetime) = arg && lifetime.is_anonymous() { - self.suggestions.push(( - lifetime.ident.span, - make_suggestion(lifetime), - )); + self.suggestions.push( + lifetime + .suggestion(&self.suggestion_param_name), + ); } } } @@ -618,7 +589,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { } } hir::TyKind::Ref(lifetime, ..) if lifetime.is_anonymous() => { - self.suggestions.push((lifetime.ident.span, make_suggestion(lifetime))); + self.suggestions.push(lifetime.suggestion(&self.suggestion_param_name)); } _ => {} } @@ -689,11 +660,7 @@ pub struct IntroducesStaticBecauseUnmetLifetimeReq { } impl Subdiagnostic for IntroducesStaticBecauseUnmetLifetimeReq { - fn add_to_diag_with>( - mut self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(mut self, diag: &mut Diag<'_, G>) { self.unmet_requirements .push_span_label(self.binding_span, fluent::trait_selection_msl_introduces_static); diag.span_note(self.unmet_requirements, fluent::trait_selection_msl_unmet_req); @@ -1008,17 +975,13 @@ pub struct ConsiderBorrowingParamHelp { } impl Subdiagnostic for ConsiderBorrowingParamHelp { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut type_param_span: MultiSpan = self.spans.clone().into(); for &span in &self.spans { // Seems like we can't call f() here as Into is required type_param_span.push_span_label(span, fluent::trait_selection_tid_consider_borrowing); } - let msg = f(diag, fluent::trait_selection_tid_param_help.into()); + let msg = diag.eagerly_translate(fluent::trait_selection_tid_param_help); diag.span_help(type_param_span, msg); } } @@ -1053,18 +1016,14 @@ pub struct DynTraitConstraintSuggestion { } impl Subdiagnostic for DynTraitConstraintSuggestion { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut multi_span: MultiSpan = vec![self.span].into(); multi_span.push_span_label(self.span, fluent::trait_selection_dtcs_has_lifetime_req_label); multi_span .push_span_label(self.ident.span, fluent::trait_selection_dtcs_introduces_requirement); - let msg = f(diag, fluent::trait_selection_dtcs_has_req_note.into()); + let msg = diag.eagerly_translate(fluent::trait_selection_dtcs_has_req_note); diag.span_note(multi_span, msg); - let msg = f(diag, fluent::trait_selection_dtcs_suggestion.into()); + let msg = diag.eagerly_translate(fluent::trait_selection_dtcs_suggestion); diag.span_suggestion_verbose( self.span.shrink_to_hi(), msg, @@ -1101,11 +1060,7 @@ pub struct ReqIntroducedLocations { } impl Subdiagnostic for ReqIntroducedLocations { - fn add_to_diag_with>( - mut self, - diag: &mut Diag<'_, G>, - f: &F, - ) { + fn add_to_diag(mut self, diag: &mut Diag<'_, G>) { for sp in self.spans { self.span.push_span_label(sp, fluent::trait_selection_ril_introduced_here); } @@ -1114,7 +1069,7 @@ impl Subdiagnostic for ReqIntroducedLocations { self.span.push_span_label(self.fn_decl_span, fluent::trait_selection_ril_introduced_by); } self.span.push_span_label(self.cause_span, fluent::trait_selection_ril_because_of); - let msg = f(diag, fluent::trait_selection_ril_static_introduced_by.into()); + let msg = diag.eagerly_translate(fluent::trait_selection_ril_static_introduced_by); diag.span_note(self.span, msg); } } @@ -1513,13 +1468,9 @@ pub struct SuggestTuplePatternMany { } impl Subdiagnostic for SuggestTuplePatternMany { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("path", self.path); - let message = f(diag, crate::fluent_generated::trait_selection_stp_wrap_many.into()); + let message = diag.eagerly_translate(fluent::trait_selection_stp_wrap_many); diag.multipart_suggestions( message, self.compatible_variants.into_iter().map(|variant| { @@ -1752,11 +1703,7 @@ pub struct AddPreciseCapturingAndParams { } impl Subdiagnostic for AddPreciseCapturingAndParams { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("new_lifetime", self.new_lifetime); diag.multipart_suggestion_verbose( fluent::trait_selection_precise_capturing_new_but_apit, @@ -1896,11 +1843,7 @@ pub struct AddPreciseCapturingForOvercapture { } impl Subdiagnostic for AddPreciseCapturingForOvercapture { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let applicability = if self.apit_spans.is_empty() { Applicability::MachineApplicable } else { diff --git a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs index 46622246a178d..aaaae14805c66 100644 --- a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs @@ -1,4 +1,4 @@ -use rustc_errors::{Diag, EmissionGuarantee, IntoDiagArg, SubdiagMessageOp, Subdiagnostic}; +use rustc_errors::{Diag, EmissionGuarantee, IntoDiagArg, Subdiagnostic}; use rustc_hir::def_id::LocalDefId; use rustc_middle::bug; use rustc_middle::ty::{self, TyCtxt}; @@ -162,17 +162,13 @@ impl RegionExplanation<'_> { } impl Subdiagnostic for RegionExplanation<'_> { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("pref_kind", self.prefix); diag.arg("suff_kind", self.suffix); diag.arg("desc_kind", self.desc.kind); diag.arg("desc_arg", self.desc.arg); - let msg = f(diag, fluent::trait_selection_region_explanation.into()); + let msg = diag.eagerly_translate(fluent::trait_selection_region_explanation); if let Some(span) = self.desc.span { diag.span_note(span, msg); } else { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c08ae168d6927..ad4e5d4dadf17 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1677,7 +1677,7 @@ fn first_non_private<'tcx>( } fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type { - let hir::Ty { hir_id, span, ref kind } = *hir_ty; + let hir::Ty { hir_id, span, ref kind, source: _ } = *hir_ty; let hir::TyKind::Path(qpath) = kind else { unreachable!() }; match qpath { diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.fixed b/src/tools/clippy/tests/ui/needless_lifetimes.fixed index d59393fb3f3c6..cb33d58817fdc 100644 --- a/src/tools/clippy/tests/ui/needless_lifetimes.fixed +++ b/src/tools/clippy/tests/ui/needless_lifetimes.fixed @@ -10,7 +10,7 @@ clippy::unnecessary_wraps, dyn_drop, clippy::get_first, - elided_named_lifetimes + mismatched_lifetime_syntaxes, )] extern crate proc_macros; diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.rs b/src/tools/clippy/tests/ui/needless_lifetimes.rs index e24907ab5fcdf..d0e15fd60e359 100644 --- a/src/tools/clippy/tests/ui/needless_lifetimes.rs +++ b/src/tools/clippy/tests/ui/needless_lifetimes.rs @@ -10,7 +10,7 @@ clippy::unnecessary_wraps, dyn_drop, clippy::get_first, - elided_named_lifetimes + mismatched_lifetime_syntaxes, )] extern crate proc_macros; diff --git a/src/tools/clippy/tests/ui/ptr_arg.rs b/src/tools/clippy/tests/ui/ptr_arg.rs index 2d77bf06ff942..65f3f05d6cb0a 100644 --- a/src/tools/clippy/tests/ui/ptr_arg.rs +++ b/src/tools/clippy/tests/ui/ptr_arg.rs @@ -312,7 +312,7 @@ mod issue_9218 { // Inferred to be `&'a str`, afaik. fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str { - //~^ ERROR: elided lifetime has a name + //~^ ERROR: lifetime flowing from input to output with different syntax todo!() } } diff --git a/src/tools/clippy/tests/ui/ptr_arg.stderr b/src/tools/clippy/tests/ui/ptr_arg.stderr index 741e60cbd749c..591b1d9b9d777 100644 --- a/src/tools/clippy/tests/ui/ptr_arg.stderr +++ b/src/tools/clippy/tests/ui/ptr_arg.stderr @@ -1,12 +1,3 @@ -error: elided lifetime has a name - --> tests/ui/ptr_arg.rs:314:56 - | -LL | fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str { - | -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a` - | - = note: `-D elided-named-lifetimes` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(elided_named_lifetimes)]` - error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do --> tests/ui/ptr_arg.rs:13:14 | @@ -240,5 +231,21 @@ error: writing `&String` instead of `&str` involves a new object where a slice w LL | fn good(v1: &String, v2: &String) { | ^^^^^^^ help: change this to: `&str` +error: lifetime flowing from input to output with different syntax + --> tests/ui/ptr_arg.rs:314:36 + | +LL | fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str { + | ^^ ^^ ---- the elided lifetime gets resolved as `'a` + | | | + | | these lifetimes flow to the output + | these lifetimes flow to the output + | + = note: `-D mismatched-lifetime-syntaxes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(mismatched_lifetime_syntaxes)]` +help: one option is to consistently use `'a` + | +LL | fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &'a str { + | ++ + error: aborting due to 27 previous errors diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs index 78d4f87ed0de6..11ef265f351eb 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"), @@ -28,6 +29,10 @@ static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[ ("deprecated-safe", "Lints for functions which were erroneously marked as safe in the past"), ]; +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 9fd33e23204e7..5d51dbae060cc 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -23,7 +23,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"), @@ -578,9 +578,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 d2ae9b1f6ef89..182667e905db0 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -2637,7 +2637,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 @@ -2670,7 +2669,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-fulldeps/internal-lints/diagnostics.rs b/tests/ui-fulldeps/internal-lints/diagnostics.rs index 442f9d72c3f19..1238fefd5bc03 100644 --- a/tests/ui-fulldeps/internal-lints/diagnostics.rs +++ b/tests/ui-fulldeps/internal-lints/diagnostics.rs @@ -15,7 +15,7 @@ extern crate rustc_span; use rustc_errors::{ Diag, DiagCtxtHandle, DiagInner, DiagMessage, Diagnostic, EmissionGuarantee, Level, - LintDiagnostic, SubdiagMessage, SubdiagMessageOp, Subdiagnostic, + LintDiagnostic, SubdiagMessage, Subdiagnostic, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::Span; @@ -56,10 +56,9 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for TranslatableInDiagnostic { pub struct UntranslatableInAddtoDiag; impl Subdiagnostic for UntranslatableInAddtoDiag { - fn add_to_diag_with>( + fn add_to_diag( self, diag: &mut Diag<'_, G>, - f: &F, ) { diag.note("untranslatable diagnostic"); //~^ ERROR diagnostics should be created using translatable messages @@ -69,10 +68,9 @@ impl Subdiagnostic for UntranslatableInAddtoDiag { pub struct TranslatableInAddtoDiag; impl Subdiagnostic for TranslatableInAddtoDiag { - fn add_to_diag_with>( + fn add_to_diag( self, diag: &mut Diag<'_, G>, - f: &F, ) { diag.note(crate::fluent_generated::no_crate_note); } diff --git a/tests/ui-fulldeps/internal-lints/diagnostics.stderr b/tests/ui-fulldeps/internal-lints/diagnostics.stderr index 36dd3cf4be798..b260c4b7afefb 100644 --- a/tests/ui-fulldeps/internal-lints/diagnostics.stderr +++ b/tests/ui-fulldeps/internal-lints/diagnostics.stderr @@ -11,19 +11,19 @@ LL | #![deny(rustc::untranslatable_diagnostic)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:64:19 + --> $DIR/diagnostics.rs:63:19 | LL | diag.note("untranslatable diagnostic"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:85:19 + --> $DIR/diagnostics.rs:83:19 | LL | diag.note("untranslatable diagnostic"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should only be created in `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls - --> $DIR/diagnostics.rs:99:21 + --> $DIR/diagnostics.rs:97:21 | LL | let _diag = dcx.struct_err(crate::fluent_generated::no_crate_example); | ^^^^^^^^^^ @@ -35,37 +35,37 @@ LL | #![deny(rustc::diagnostic_outside_of_impl)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should only be created in `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls - --> $DIR/diagnostics.rs:102:21 + --> $DIR/diagnostics.rs:100:21 | LL | let _diag = dcx.struct_err("untranslatable diagnostic"); | ^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:102:32 + --> $DIR/diagnostics.rs:100:32 | LL | let _diag = dcx.struct_err("untranslatable diagnostic"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:120:7 + --> $DIR/diagnostics.rs:118:7 | LL | f("untranslatable diagnostic", crate::fluent_generated::no_crate_example); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:122:50 + --> $DIR/diagnostics.rs:120:50 | LL | f(crate::fluent_generated::no_crate_example, "untranslatable diagnostic"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:124:7 + --> $DIR/diagnostics.rs:122:7 | LL | f("untranslatable diagnostic", "untranslatable diagnostic"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:124:36 + --> $DIR/diagnostics.rs:122:36 | LL | f("untranslatable diagnostic", "untranslatable diagnostic"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/issues/issue-63388-1.rs b/tests/ui/async-await/issues/issue-63388-1.rs index acfc64baff97d..3a89f3ebfd2b4 100644 --- a/tests/ui/async-await/issues/issue-63388-1.rs +++ b/tests/ui/async-await/issues/issue-63388-1.rs @@ -9,7 +9,7 @@ trait Foo {} impl Xyz { async fn do_sth<'a>( &'a self, foo: &dyn Foo - ) -> &dyn Foo //~ WARNING elided lifetime has a name + ) -> &dyn Foo { foo //~^ ERROR explicit lifetime required in the type of `foo` [E0621] diff --git a/tests/ui/async-await/issues/issue-63388-1.stderr b/tests/ui/async-await/issues/issue-63388-1.stderr index 579caa45bc945..277f7fa6f63ed 100644 --- a/tests/ui/async-await/issues/issue-63388-1.stderr +++ b/tests/ui/async-await/issues/issue-63388-1.stderr @@ -1,14 +1,3 @@ -warning: elided lifetime has a name - --> $DIR/issue-63388-1.rs:12:10 - | -LL | async fn do_sth<'a>( - | -- lifetime `'a` declared here -LL | &'a self, foo: &dyn Foo -LL | ) -> &dyn Foo - | ^ this elided lifetime gets resolved as `'a` - | - = note: `#[warn(elided_named_lifetimes)]` on by default - error[E0621]: explicit lifetime required in the type of `foo` --> $DIR/issue-63388-1.rs:14:9 | @@ -18,6 +7,6 @@ LL | &'a self, foo: &dyn Foo LL | foo | ^^^ lifetime `'a` required -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0621`. diff --git a/tests/ui/const-generics/type-dependent/issue-71348.full.stderr b/tests/ui/const-generics/type-dependent/issue-71348.full.stderr index 177ff20fbf9ea..b5c0515057fba 100644 --- a/tests/ui/const-generics/type-dependent/issue-71348.full.stderr +++ b/tests/ui/const-generics/type-dependent/issue-71348.full.stderr @@ -1,10 +1,17 @@ -warning: elided lifetime has a name - --> $DIR/issue-71348.rs:18:68 +warning: lifetime flowing from input to output with different syntax + --> $DIR/issue-71348.rs:18:40 | LL | fn ask<'a, const N: &'static str>(&'a self) -> &'a >::Target - | -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a` + | ^^ -- ------------------------ the elided lifetimes get resolved as `'a` + | | | + | | the elided lifetimes get resolved as `'a` + | this lifetime flows to the output | - = note: `#[warn(elided_named_lifetimes)]` on by default + = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default +help: one option is to consistently use `'a` + | +LL | fn ask<'a, const N: &'static str>(&'a self) -> &'a >::Target + | +++ warning: 1 warning emitted diff --git a/tests/ui/const-generics/type-dependent/issue-71348.min.stderr b/tests/ui/const-generics/type-dependent/issue-71348.min.stderr index 8995c4158635f..c491469bcbd2d 100644 --- a/tests/ui/const-generics/type-dependent/issue-71348.min.stderr +++ b/tests/ui/const-generics/type-dependent/issue-71348.min.stderr @@ -1,11 +1,3 @@ -warning: elided lifetime has a name - --> $DIR/issue-71348.rs:18:68 - | -LL | fn ask<'a, const N: &'static str>(&'a self) -> &'a >::Target - | -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a` - | - = note: `#[warn(elided_named_lifetimes)]` on by default - error: `&'static str` is forbidden as the type of a const generic parameter --> $DIR/issue-71348.rs:10:24 | @@ -38,5 +30,5 @@ help: add `#![feature(unsized_const_params)]` to the crate attributes to enable LL + #![feature(unsized_const_params)] | -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/type-dependent/issue-71348.rs b/tests/ui/const-generics/type-dependent/issue-71348.rs index 97e786405fe39..c6563c8030590 100644 --- a/tests/ui/const-generics/type-dependent/issue-71348.rs +++ b/tests/ui/const-generics/type-dependent/issue-71348.rs @@ -17,7 +17,7 @@ trait Get<'a, const N: &'static str> { impl Foo { fn ask<'a, const N: &'static str>(&'a self) -> &'a >::Target //[min]~^ ERROR `&'static str` is forbidden as the type of a const generic parameter - //~^^ WARNING elided lifetime has a name + //[full]~^^ WARNING lifetime flowing from input to output with different syntax where Self: Get<'a, N>, { diff --git a/tests/ui/generics/generic-no-mangle.fixed b/tests/ui/generics/generic-no-mangle.fixed index 2776848c45fff..e3e41eb9d0db1 100644 --- a/tests/ui/generics/generic-no-mangle.fixed +++ b/tests/ui/generics/generic-no-mangle.fixed @@ -1,5 +1,5 @@ //@ run-rustfix -#![allow(dead_code, elided_named_lifetimes)] +#![allow(dead_code, mismatched_lifetime_syntaxes)] #![deny(no_mangle_generic_items)] pub fn foo() {} //~ ERROR functions generic over types or consts must be mangled diff --git a/tests/ui/generics/generic-no-mangle.rs b/tests/ui/generics/generic-no-mangle.rs index 5314005d31fa1..085f8610a548e 100644 --- a/tests/ui/generics/generic-no-mangle.rs +++ b/tests/ui/generics/generic-no-mangle.rs @@ -1,5 +1,5 @@ //@ run-rustfix -#![allow(dead_code, elided_named_lifetimes)] +#![allow(dead_code, mismatched_lifetime_syntaxes)] #![deny(no_mangle_generic_items)] #[no_mangle] diff --git a/tests/ui/impl-trait/impl-fn-hrtb-bounds.rs b/tests/ui/impl-trait/impl-fn-hrtb-bounds.rs index a7f38b5c16af2..da7530b4e7a8c 100644 --- a/tests/ui/impl-trait/impl-fn-hrtb-bounds.rs +++ b/tests/ui/impl-trait/impl-fn-hrtb-bounds.rs @@ -13,7 +13,6 @@ fn b() -> impl for<'a> Fn(&'a u8) -> (impl Debug + 'a) { fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) { //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` - //~| WARNING elided lifetime has a name |x| x } diff --git a/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr b/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr index 31f39eb90041e..40cb6b647d1e9 100644 --- a/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr +++ b/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr @@ -1,5 +1,5 @@ error[E0106]: missing lifetime specifier - --> $DIR/impl-fn-hrtb-bounds.rs:20:38 + --> $DIR/impl-fn-hrtb-bounds.rs:19:38 | LL | fn d() -> impl Fn() -> (impl Debug + '_) { | ^^ expected named lifetime parameter @@ -11,14 +11,6 @@ LL - fn d() -> impl Fn() -> (impl Debug + '_) { LL + fn d() -> impl Fn() -> (impl Debug + 'static) { | -warning: elided lifetime has a name - --> $DIR/impl-fn-hrtb-bounds.rs:14:52 - | -LL | fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) { - | -- lifetime `'a` declared here ^^ this elided lifetime gets resolved as `'a` - | - = note: `#[warn(elided_named_lifetimes)]` on by default - error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` --> $DIR/impl-fn-hrtb-bounds.rs:4:41 | @@ -55,7 +47,7 @@ note: lifetime declared here LL | fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) { | ^^ -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 4 previous errors Some errors have detailed explanations: E0106, E0657. For more information about an error, try `rustc --explain E0106`. diff --git a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs index 776bb7278ce15..199cbbf4fcc9b 100644 --- a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs +++ b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs @@ -2,7 +2,6 @@ use std::fmt::Debug; fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) { - //~^ WARNING elided lifetime has a name |x| x //~^ ERROR expected generic lifetime parameter, found `'_` } diff --git a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr index 209186db4cc15..6064b09ef0927 100644 --- a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr +++ b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr @@ -1,20 +1,11 @@ -warning: elided lifetime has a name - --> $DIR/impl-fn-predefined-lifetimes.rs:4:48 - | -LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) { - | -- lifetime `'a` declared here ^^ this elided lifetime gets resolved as `'a` - | - = note: `#[warn(elided_named_lifetimes)]` on by default - error[E0792]: expected generic lifetime parameter, found `'_` - --> $DIR/impl-fn-predefined-lifetimes.rs:6:9 + --> $DIR/impl-fn-predefined-lifetimes.rs:5:9 | LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) { | -- this generic parameter must be used with a generic lifetime parameter -LL | LL | |x| x | ^ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs index e48441f533d7c..1ac3c593dbe5c 100644 --- a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs +++ b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs @@ -1,7 +1,7 @@ //@ check-pass pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator { - //~^ WARNING elided lifetime has a name + //~^ WARNING lifetime flowing from input to output with different syntax v.into_iter() } diff --git a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr index bff3ffd934ac6..01806f3217eaa 100644 --- a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr +++ b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr @@ -1,10 +1,14 @@ -warning: elided lifetime has a name - --> $DIR/rpit-assoc-pair-with-lifetime.rs:3:82 +warning: lifetime flowing from input to output with different syntax + --> $DIR/rpit-assoc-pair-with-lifetime.rs:3:31 | LL | pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator { - | -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a` + | ^^ this lifetime flows to the output ---- the elided lifetime gets resolved as `'a` | - = note: `#[warn(elided_named_lifetimes)]` on by default + = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default +help: one option is to consistently use `'a` + | +LL | pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator { + | ++ warning: 1 warning emitted 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..26fcf278f5dd0 --- /dev/null +++ b/tests/ui/lifetimes/hidden-lifetimes-in-type-paths.rs @@ -0,0 +1,52 @@ +#![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 {} + +// ========== + +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(); +} 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..5eae5a87cd413 --- /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:31: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:35: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:38: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:41: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:44: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/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.rs b/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.rs index 63a2c9be9ebad..d0a8fe795efd0 100644 --- a/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.rs +++ b/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.rs @@ -47,6 +47,5 @@ fn l<'a>(_: &'a str, _: &'a str) -> &str { "" } // This is ok because both `'a` are for the same parameter. fn m<'a>(_: &'a Foo<'a>) -> &str { "" } -//~^ WARNING elided lifetime has a name fn main() {} diff --git a/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr b/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr index f835d2655bb01..23ef36888f079 100644 --- a/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr +++ b/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr @@ -105,16 +105,6 @@ help: consider using the `'a` lifetime LL | fn l<'a>(_: &'a str, _: &'a str) -> &'a str { "" } | ++ -warning: elided lifetime has a name - --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:49:29 - | -LL | fn m<'a>(_: &'a Foo<'a>) -> &str { "" } - | -- ^ this elided lifetime gets resolved as `'a` - | | - | lifetime `'a` declared here - | - = note: `#[warn(elided_named_lifetimes)]` on by default - -error: aborting due to 7 previous errors; 1 warning emitted +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0106`. diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.rs b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.rs index 598633d75768e..5dbc0c556fb52 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.rs +++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.rs @@ -4,12 +4,8 @@ struct Foo { impl Foo { fn foo<'a>(&'a self, x: &i32) -> &i32 { - //~^ WARNING elided lifetime has a name - if true { &self.field } else { x } //~ ERROR explicit lifetime - } - } fn main() { } diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr index 2d5d4fb0e72ec..071bda24ef8de 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr @@ -1,22 +1,11 @@ -warning: elided lifetime has a name - --> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:6:36 - | -LL | fn foo<'a>(&'a self, x: &i32) -> &i32 { - | -- ^ this elided lifetime gets resolved as `'a` - | | - | lifetime `'a` declared here - | - = note: `#[warn(elided_named_lifetimes)]` on by default - error[E0621]: explicit lifetime required in the type of `x` - --> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:9:36 + --> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:7:36 | LL | fn foo<'a>(&'a self, x: &i32) -> &i32 { | ---- help: add explicit lifetime `'a` to the type of `x`: `&'a i32` -... LL | if true { &self.field } else { x } | ^ lifetime `'a` required -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0621`. diff --git a/tests/ui/lint/elided-named-lifetimes/example-from-issue48686.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.rs similarity index 55% rename from tests/ui/lint/elided-named-lifetimes/example-from-issue48686.rs rename to tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.rs index eac7c32a9aac6..1804003d36722 100644 --- a/tests/ui/lint/elided-named-lifetimes/example-from-issue48686.rs +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.rs @@ -1,10 +1,10 @@ -#![deny(elided_named_lifetimes)] +#![deny(mismatched_lifetime_syntaxes)] struct Foo; impl Foo { pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 { - //~^ ERROR elided lifetime has a name + //~^ ERROR lifetime flowing from input to output with different syntax unsafe { &mut *(x as *mut _) } } } diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr new file mode 100644 index 0000000000000..68e76e78c9dc9 --- /dev/null +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr @@ -0,0 +1,20 @@ +error: lifetime flowing from input to output with different syntax + --> $DIR/example-from-issue48686.rs:6:21 + | +LL | pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 { + | ^^^^^^^ ------- the elided lifetime gets resolved as `'static` + | | + | this lifetime flows to the output + | +note: the lint level is defined here + --> $DIR/example-from-issue48686.rs:1:9 + | +LL | #![deny(mismatched_lifetime_syntaxes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: one option is to consistently use `'static` + | +LL | pub fn get_mut(&'static self, x: &mut u8) -> &'static mut u8 { + | +++++++ + +error: aborting due to 1 previous error + diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.rs new file mode 100644 index 0000000000000..3d5aab5c8295b --- /dev/null +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.rs @@ -0,0 +1,27 @@ +#![deny(mismatched_lifetime_syntaxes)] + +fn ampersand<'a>(x: &'a u8) -> &u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + x +} + +struct Brackets<'a>(&'a u8); + +fn brackets<'a>(x: &'a u8) -> Brackets { + //~^ ERROR lifetime flowing from input to output with different syntax + Brackets(x) +} + +struct Comma<'a, T>(&'a T); + +fn comma<'a>(x: &'a u8) -> Comma { + //~^ ERROR lifetime flowing from input to output with different syntax + Comma(x) +} + +fn underscore<'a>(x: &'a u8) -> &'_ u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + x +} + +fn main() {} diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr new file mode 100644 index 0000000000000..04aa634802bb5 --- /dev/null +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr @@ -0,0 +1,60 @@ +error: lifetime flowing from input to output with different syntax + --> $DIR/missing-lifetime-kind.rs:3:22 + | +LL | fn ampersand<'a>(x: &'a u8) -> &u8 { + | ^^ --- the elided lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +note: the lint level is defined here + --> $DIR/missing-lifetime-kind.rs:1:9 + | +LL | #![deny(mismatched_lifetime_syntaxes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: one option is to consistently use `'a` + | +LL | fn ampersand<'a>(x: &'a u8) -> &'a u8 { + | ++ + +error: lifetime flowing from input to output with different syntax + --> $DIR/missing-lifetime-kind.rs:10:21 + | +LL | fn brackets<'a>(x: &'a u8) -> Brackets { + | ^^ -------- the elided lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL | fn brackets<'a>(x: &'a u8) -> Brackets<'a> { + | ++++ + +error: lifetime flowing from input to output with different syntax + --> $DIR/missing-lifetime-kind.rs:17:18 + | +LL | fn comma<'a>(x: &'a u8) -> Comma { + | ^^ --------- the elided lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL | fn comma<'a>(x: &'a u8) -> Comma<'a, u8> { + | +++ + +error: lifetime flowing from input to output with different syntax + --> $DIR/missing-lifetime-kind.rs:22:23 + | +LL | fn underscore<'a>(x: &'a u8) -> &'_ u8 { + | ^^ -- the elided lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL - fn underscore<'a>(x: &'a u8) -> &'_ u8 { +LL + fn underscore<'a>(x: &'a u8) -> &'a u8 { + | + +error: aborting due to 4 previous errors + diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.rs new file mode 100644 index 0000000000000..d63a6315ac81b --- /dev/null +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.rs @@ -0,0 +1,17 @@ +#![allow(mismatched_lifetime_syntaxes)] + +#[warn(mismatched_lifetime_syntaxes)] +mod foo { + fn bar(x: &'static u8) -> &u8 { + //~^ WARNING lifetime flowing from input to output with different syntax + x + } + + #[deny(mismatched_lifetime_syntaxes)] + fn baz(x: &'static u8) -> &u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + x + } +} + +fn main() {} diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr new file mode 100644 index 0000000000000..226a83d0363a6 --- /dev/null +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr @@ -0,0 +1,38 @@ +warning: lifetime flowing from input to output with different syntax + --> $DIR/not-tied-to-crate.rs:5:16 + | +LL | fn bar(x: &'static u8) -> &u8 { + | ^^^^^^^ --- the elided lifetime gets resolved as `'static` + | | + | this lifetime flows to the output + | +note: the lint level is defined here + --> $DIR/not-tied-to-crate.rs:3:8 + | +LL | #[warn(mismatched_lifetime_syntaxes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: one option is to consistently use `'static` + | +LL | fn bar(x: &'static u8) -> &'static u8 { + | +++++++ + +error: lifetime flowing from input to output with different syntax + --> $DIR/not-tied-to-crate.rs:11:16 + | +LL | fn baz(x: &'static u8) -> &u8 { + | ^^^^^^^ --- the elided lifetime gets resolved as `'static` + | | + | this lifetime flows to the output + | +note: the lint level is defined here + --> $DIR/not-tied-to-crate.rs:10:12 + | +LL | #[deny(mismatched_lifetime_syntaxes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: one option is to consistently use `'static` + | +LL | fn baz(x: &'static u8) -> &'static u8 { + | +++++++ + +error: aborting due to 1 previous error; 1 warning emitted + diff --git a/tests/ui/lint/elided-named-lifetimes/static.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.rs similarity index 63% rename from tests/ui/lint/elided-named-lifetimes/static.rs rename to tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.rs index dc8222c6e6e48..47ae258f138fc 100644 --- a/tests/ui/lint/elided-named-lifetimes/static.rs +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.rs @@ -1,4 +1,4 @@ -#![deny(elided_named_lifetimes)] +#![deny(mismatched_lifetime_syntaxes)] use std::borrow::Cow; @@ -14,26 +14,26 @@ impl Trait for () { } fn ampersand(x: &'static u8) -> &u8 { - //~^ ERROR elided lifetime has a name + //~^ ERROR lifetime flowing from input to output with different syntax x } struct Brackets<'a>(&'a u8); fn brackets(x: &'static u8) -> Brackets { - //~^ ERROR elided lifetime has a name + //~^ ERROR lifetime flowing from input to output with different syntax Brackets(x) } struct Comma<'a, T>(&'a T); fn comma(x: &'static u8) -> Comma { - //~^ ERROR elided lifetime has a name + //~^ ERROR lifetime flowing from input to output with different syntax Comma(x) } fn underscore(x: &'static u8) -> &'_ u8 { - //~^ ERROR elided lifetime has a name + //~^ ERROR lifetime flowing from input to output with different syntax x } diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr new file mode 100644 index 0000000000000..5efd68d83a66a --- /dev/null +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr @@ -0,0 +1,60 @@ +error: lifetime flowing from input to output with different syntax + --> $DIR/static.rs:16:18 + | +LL | fn ampersand(x: &'static u8) -> &u8 { + | ^^^^^^^ --- the elided lifetime gets resolved as `'static` + | | + | this lifetime flows to the output + | +note: the lint level is defined here + --> $DIR/static.rs:1:9 + | +LL | #![deny(mismatched_lifetime_syntaxes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: one option is to consistently use `'static` + | +LL | fn ampersand(x: &'static u8) -> &'static u8 { + | +++++++ + +error: lifetime flowing from input to output with different syntax + --> $DIR/static.rs:23:17 + | +LL | fn brackets(x: &'static u8) -> Brackets { + | ^^^^^^^ -------- the elided lifetime gets resolved as `'static` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'static` + | +LL | fn brackets(x: &'static u8) -> Brackets<'static> { + | +++++++++ + +error: lifetime flowing from input to output with different syntax + --> $DIR/static.rs:30:14 + | +LL | fn comma(x: &'static u8) -> Comma { + | ^^^^^^^ --------- the elided lifetime gets resolved as `'static` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'static` + | +LL | fn comma(x: &'static u8) -> Comma<'static, u8> { + | ++++++++ + +error: lifetime flowing from input to output with different syntax + --> $DIR/static.rs:35:19 + | +LL | fn underscore(x: &'static u8) -> &'_ u8 { + | ^^^^^^^ -- the elided lifetime gets resolved as `'static` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'static` + | +LL - fn underscore(x: &'static u8) -> &'_ u8 { +LL + fn underscore(x: &'static u8) -> &'static u8 { + | + +error: aborting due to 4 previous errors + diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs new file mode 100644 index 0000000000000..b0e822dc054e5 --- /dev/null +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs @@ -0,0 +1,290 @@ +#![deny(mismatched_lifetime_syntaxes)] + +// +// + +#[derive(Copy, Clone)] +struct ContainsLifetime<'a>(&'a u8); + +struct S(u8); + +fn named_ref_to_hidden_ref<'a>(v: &'a u8) -> &u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + v +} + +fn named_ref_to_anonymous_ref<'a>(v: &'a u8) -> &'_ u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + v +} + +// --- + +fn hidden_path_to_anonymous_path(v: ContainsLifetime) -> ContainsLifetime<'_> { + //~^ ERROR lifetime flowing from input to output with different syntax + v +} + +fn anonymous_path_to_hidden_path(v: ContainsLifetime<'_>) -> ContainsLifetime { + //~^ ERROR lifetime flowing from input to output with different syntax + v +} + +fn named_path_to_hidden_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime { + //~^ ERROR lifetime flowing from input to output with different syntax + v +} + +fn named_path_to_anonymous_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime<'_> { + //~^ ERROR lifetime flowing from input to output with different syntax + v +} + +// --- + +fn anonymous_ref_to_hidden_path(v: &'_ u8) -> ContainsLifetime { + //~^ ERROR lifetime flowing from input to output with different syntax + ContainsLifetime(v) +} + +fn named_ref_to_hidden_path<'a>(v: &'a u8) -> ContainsLifetime { + //~^ ERROR lifetime flowing from input to output with different syntax + ContainsLifetime(v) +} + +fn named_ref_to_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'_> { + //~^ ERROR lifetime flowing from input to output with different syntax + ContainsLifetime(v) +} + +// --- + +fn hidden_path_to_anonymous_ref(v: ContainsLifetime) -> &'_ u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + v.0 +} + +fn named_path_to_hidden_ref<'a>(v: ContainsLifetime<'a>) -> &u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + v.0 +} + +fn named_path_to_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'_ u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + v.0 +} + +impl S { + fn method_named_ref_to_hidden_ref<'a>(&'a self) -> &u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + &self.0 + } + + fn method_named_ref_to_anonymous_ref<'a>(&'a self) -> &'_ u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + &self.0 + } + + // --- + + fn method_anonymous_ref_to_hidden_path(&'_ self) -> ContainsLifetime { + //~^ ERROR lifetime flowing from input to output with different syntax + ContainsLifetime(&self.0) + } + + fn method_named_ref_to_hidden_path<'a>(&'a self) -> ContainsLifetime { + //~^ ERROR lifetime flowing from input to output with different syntax + ContainsLifetime(&self.0) + } + + fn method_named_ref_to_anonymous_path<'a>(&'a self) -> ContainsLifetime<'_> { + //~^ ERROR lifetime flowing from input to output with different syntax + ContainsLifetime(&self.0) + } +} + +// If a function uses the `'static` named lifetime, we should not +// suggest replacing it with an anonymous or hidden lifetime. Only +// suggest using `'static` everywhere. +mod static_suggestions { + #[derive(Copy, Clone)] + struct ContainsLifetime<'a>(&'a u8); + + struct S(u8); + + fn static_ref_to_hidden_ref(v: &'static u8) -> &u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + v + } + + fn static_ref_to_anonymous_ref(v: &'static u8) -> &'_ u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + v + } + + fn static_ref_to_hidden_path(v: &'static u8) -> ContainsLifetime { + //~^ ERROR lifetime flowing from input to output with different syntax + ContainsLifetime(v) + } + + fn static_ref_to_anonymous_path(v: &'static u8) -> ContainsLifetime<'_> { + //~^ ERROR lifetime flowing from input to output with different syntax + ContainsLifetime(v) + } + + impl S { + fn static_ref_to_hidden_ref(&'static self) -> &u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + &self.0 + } + + fn static_ref_to_anonymous_ref(&'static self) -> &'_ u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + &self.0 + } + + fn static_ref_to_hidden_path(&'static self) -> ContainsLifetime { + //~^ ERROR lifetime flowing from input to output with different syntax + ContainsLifetime(&self.0) + } + + fn static_ref_to_anonymous_path(&'static self) -> ContainsLifetime<'_> { + //~^ ERROR lifetime flowing from input to output with different syntax + ContainsLifetime(&self.0) + } + } +} + +/// `impl Trait` uses lifetimes in some additional ways. +mod impl_trait { + #[derive(Copy, Clone)] + struct ContainsLifetime<'a>(&'a u8); + + fn named_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + '_ { + //~^ ERROR lifetime flowing from input to output with different syntax + move || _ = v + } + + fn named_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'_> { + //~^ ERROR lifetime flowing from input to output with different syntax + move || _ = v + } + + fn named_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + '_ { + //~^ ERROR lifetime flowing from input to output with different syntax + move || _ = v + } + + fn named_path_to_impl_trait_precise_capture<'a>( + v: ContainsLifetime<'a>, + //~^ ERROR lifetime flowing from input to output with different syntax + ) -> impl FnOnce() + use<'_> { + move || _ = v + } +} + +/// These tests serve to exercise edge cases of the lint formatting +mod diagnostic_output { + fn multiple_outputs<'a>(v: &'a u8) -> (&u8, &u8) { + //~^ ERROR lifetime flowing from input to output with different syntax + (v, v) + } +} + +/// These usages are expected to **not** trigger the lint +mod acceptable_uses { + #[derive(Copy, Clone)] + struct ContainsLifetime<'a>(&'a u8); + + struct S(u8); + + fn hidden_ref_to_hidden_ref(v: &u8) -> &u8 { + v + } + + fn anonymous_ref_to_anonymous_ref(v: &'_ u8) -> &'_ u8 { + v + } + + fn named_ref_to_named_ref<'a>(v: &'a u8) -> &'a u8 { + v + } + + fn hidden_path_to_hidden_path(v: ContainsLifetime) -> ContainsLifetime { + v + } + + fn anonymous_path_to_anonymous_path(v: ContainsLifetime<'_>) -> ContainsLifetime<'_> { + v + } + + fn named_path_to_named_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime<'a> { + v + } + + fn hidden_ref_to_hidden_path(v: &u8) -> ContainsLifetime { + ContainsLifetime(v) + } + + fn anonymous_ref_to_anonymous_path(v: &'_ u8) -> ContainsLifetime<'_> { + ContainsLifetime(v) + } + + fn named_ref_to_named_path<'a>(v: &'a u8) -> ContainsLifetime<'a> { + ContainsLifetime(v) + } + + fn hidden_path_to_hidden_ref(v: ContainsLifetime) -> &u8 { + v.0 + } + + fn anonymous_path_to_anonymous_ref(v: ContainsLifetime<'_>) -> &'_ u8 { + v.0 + } + + fn named_path_to_named_ref<'a>(v: ContainsLifetime<'a>) -> &'a u8 { + v.0 + } + + // These may be surprising, but ampersands count as enough of a + // visual indicator that a reference exists that we treat + // references with hidden lifetimes the same as if they were + // anonymous. + fn hidden_ref_to_anonymous_ref(v: &u8) -> &'_ u8 { + v + } + + fn anonymous_ref_to_hidden_ref(v: &'_ u8) -> &u8 { + v + } + + fn hidden_ref_to_anonymous_path(v: &u8) -> ContainsLifetime<'_> { + ContainsLifetime(v) + } + + fn anonymous_path_to_hidden_ref(v: ContainsLifetime<'_>) -> &u8 { + v.0 + } + + impl S { + fn method_hidden_ref_to_anonymous_ref(&self) -> &'_ u8 { + &self.0 + } + + fn method_anonymous_ref_to_hidden_ref(&'_ self) -> &u8 { + &self.0 + } + + fn method_hidden_ref_to_anonymous_path(&self) -> ContainsLifetime<'_> { + ContainsLifetime(&self.0) + } + } + + // `dyn Trait` has an "embedded" lifetime that we should **not** + // lint about. + fn dyn_trait_does_not_have_a_lifetime_generic(v: &u8) -> &dyn core::fmt::Debug { + v + } +} + +fn main() {} diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr new file mode 100644 index 0000000000000..212e924a98d60 --- /dev/null +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr @@ -0,0 +1,413 @@ +error: lifetime flowing from input to output with different syntax + --> $DIR/mismatched-lifetime-syntaxes.rs:11:36 + | +LL | fn named_ref_to_hidden_ref<'a>(v: &'a u8) -> &u8 { + | ^^ --- the elided lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +note: the lint level is defined here + --> $DIR/mismatched-lifetime-syntaxes.rs:1:9 + | +LL | #![deny(mismatched_lifetime_syntaxes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: one option is to consistently use `'a` + | +LL | fn named_ref_to_hidden_ref<'a>(v: &'a u8) -> &'a u8 { + | ++ + +error: lifetime flowing from input to output with different syntax + --> $DIR/mismatched-lifetime-syntaxes.rs:16:39 + | +LL | fn named_ref_to_anonymous_ref<'a>(v: &'a u8) -> &'_ u8 { + | ^^ -- the elided lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL - fn named_ref_to_anonymous_ref<'a>(v: &'a u8) -> &'_ u8 { +LL + fn named_ref_to_anonymous_ref<'a>(v: &'a u8) -> &'a u8 { + | + +error: lifetime flowing from input to output with different syntax + --> $DIR/mismatched-lifetime-syntaxes.rs:23:37 + | +LL | fn hidden_path_to_anonymous_path(v: ContainsLifetime) -> ContainsLifetime<'_> { + | ^^^^^^^^^^^^^^^^ -- the elided lifetime gets resolved as `'_` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'_` + | +LL | fn hidden_path_to_anonymous_path(v: ContainsLifetime<'_>) -> ContainsLifetime<'_> { + | ++++ + +error: lifetime flowing from input to output with different syntax + --> $DIR/mismatched-lifetime-syntaxes.rs:28:54 + | +LL | fn anonymous_path_to_hidden_path(v: ContainsLifetime<'_>) -> ContainsLifetime { + | ^^ ---------------- the elided lifetime gets resolved as `'_` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'_` + | +LL | fn anonymous_path_to_hidden_path(v: ContainsLifetime<'_>) -> ContainsLifetime<'_> { + | ++++ + +error: lifetime flowing from input to output with different syntax + --> $DIR/mismatched-lifetime-syntaxes.rs:33:54 + | +LL | fn named_path_to_hidden_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime { + | ^^ ---------------- the elided lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL | fn named_path_to_hidden_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime<'a> { + | ++++ + +error: lifetime flowing from input to output with different syntax + --> $DIR/mismatched-lifetime-syntaxes.rs:38:57 + | +LL | fn named_path_to_anonymous_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime<'_> { + | ^^ -- the elided lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL - fn named_path_to_anonymous_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime<'_> { +LL + fn named_path_to_anonymous_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime<'a> { + | + +error: lifetime flowing from input to output with different syntax + --> $DIR/mismatched-lifetime-syntaxes.rs:45:37 + | +LL | fn anonymous_ref_to_hidden_path(v: &'_ u8) -> ContainsLifetime { + | ^^ ---------------- the elided lifetime gets resolved as `'_` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'_` + | +LL | fn anonymous_ref_to_hidden_path(v: &'_ u8) -> ContainsLifetime<'_> { + | ++++ + +error: lifetime flowing from input to output with different syntax + --> $DIR/mismatched-lifetime-syntaxes.rs:50:37 + | +LL | fn named_ref_to_hidden_path<'a>(v: &'a u8) -> ContainsLifetime { + | ^^ ---------------- the elided lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL | fn named_ref_to_hidden_path<'a>(v: &'a u8) -> ContainsLifetime<'a> { + | ++++ + +error: lifetime flowing from input to output with different syntax + --> $DIR/mismatched-lifetime-syntaxes.rs:55:40 + | +LL | fn named_ref_to_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'_> { + | ^^ -- the elided lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL - fn named_ref_to_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'_> { +LL + fn named_ref_to_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'a> { + | + +error: lifetime flowing from input to output with different syntax + --> $DIR/mismatched-lifetime-syntaxes.rs:62:36 + | +LL | fn hidden_path_to_anonymous_ref(v: ContainsLifetime) -> &'_ u8 { + | ^^^^^^^^^^^^^^^^ -- the elided lifetime gets resolved as `'_` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'_` + | +LL | fn hidden_path_to_anonymous_ref(v: ContainsLifetime<'_>) -> &'_ u8 { + | ++++ + +error: lifetime flowing from input to output with different syntax + --> $DIR/mismatched-lifetime-syntaxes.rs:67:53 + | +LL | fn named_path_to_hidden_ref<'a>(v: ContainsLifetime<'a>) -> &u8 { + | ^^ --- the elided lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL | fn named_path_to_hidden_ref<'a>(v: ContainsLifetime<'a>) -> &'a u8 { + | ++ + +error: lifetime flowing from input to output with different syntax + --> $DIR/mismatched-lifetime-syntaxes.rs:72:56 + | +LL | fn named_path_to_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'_ u8 { + | ^^ -- the elided lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL - fn named_path_to_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'_ u8 { +LL + fn named_path_to_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'a u8 { + | + +error: lifetime flowing from input to output with different syntax + --> $DIR/mismatched-lifetime-syntaxes.rs:78:44 + | +LL | fn method_named_ref_to_hidden_ref<'a>(&'a self) -> &u8 { + | ^^ --- the elided lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL | fn method_named_ref_to_hidden_ref<'a>(&'a self) -> &'a u8 { + | ++ + +error: lifetime flowing from input to output with different syntax + --> $DIR/mismatched-lifetime-syntaxes.rs:83:47 + | +LL | fn method_named_ref_to_anonymous_ref<'a>(&'a self) -> &'_ u8 { + | ^^ -- the elided lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL - fn method_named_ref_to_anonymous_ref<'a>(&'a self) -> &'_ u8 { +LL + fn method_named_ref_to_anonymous_ref<'a>(&'a self) -> &'a u8 { + | + +error: lifetime flowing from input to output with different syntax + --> $DIR/mismatched-lifetime-syntaxes.rs:90:45 + | +LL | fn method_anonymous_ref_to_hidden_path(&'_ self) -> ContainsLifetime { + | ^^ ---------------- the elided lifetime gets resolved as `'_` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'_` + | +LL | fn method_anonymous_ref_to_hidden_path(&'_ self) -> ContainsLifetime<'_> { + | ++++ + +error: lifetime flowing from input to output with different syntax + --> $DIR/mismatched-lifetime-syntaxes.rs:95:45 + | +LL | fn method_named_ref_to_hidden_path<'a>(&'a self) -> ContainsLifetime { + | ^^ ---------------- the elided lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL | fn method_named_ref_to_hidden_path<'a>(&'a self) -> ContainsLifetime<'a> { + | ++++ + +error: lifetime flowing from input to output with different syntax + --> $DIR/mismatched-lifetime-syntaxes.rs:100:48 + | +LL | fn method_named_ref_to_anonymous_path<'a>(&'a self) -> ContainsLifetime<'_> { + | ^^ -- the elided lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL - fn method_named_ref_to_anonymous_path<'a>(&'a self) -> ContainsLifetime<'_> { +LL + fn method_named_ref_to_anonymous_path<'a>(&'a self) -> ContainsLifetime<'a> { + | + +error: lifetime flowing from input to output with different syntax + --> $DIR/mismatched-lifetime-syntaxes.rs:115:37 + | +LL | fn static_ref_to_hidden_ref(v: &'static u8) -> &u8 { + | ^^^^^^^ --- the elided lifetime gets resolved as `'static` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'static` + | +LL | fn static_ref_to_hidden_ref(v: &'static u8) -> &'static u8 { + | +++++++ + +error: lifetime flowing from input to output with different syntax + --> $DIR/mismatched-lifetime-syntaxes.rs:120:40 + | +LL | fn static_ref_to_anonymous_ref(v: &'static u8) -> &'_ u8 { + | ^^^^^^^ -- the elided lifetime gets resolved as `'static` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'static` + | +LL - fn static_ref_to_anonymous_ref(v: &'static u8) -> &'_ u8 { +LL + fn static_ref_to_anonymous_ref(v: &'static u8) -> &'static u8 { + | + +error: lifetime flowing from input to output with different syntax + --> $DIR/mismatched-lifetime-syntaxes.rs:125:38 + | +LL | fn static_ref_to_hidden_path(v: &'static u8) -> ContainsLifetime { + | ^^^^^^^ ---------------- the elided lifetime gets resolved as `'static` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'static` + | +LL | fn static_ref_to_hidden_path(v: &'static u8) -> ContainsLifetime<'static> { + | +++++++++ + +error: lifetime flowing from input to output with different syntax + --> $DIR/mismatched-lifetime-syntaxes.rs:130:41 + | +LL | fn static_ref_to_anonymous_path(v: &'static u8) -> ContainsLifetime<'_> { + | ^^^^^^^ -- the elided lifetime gets resolved as `'static` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'static` + | +LL - fn static_ref_to_anonymous_path(v: &'static u8) -> ContainsLifetime<'_> { +LL + fn static_ref_to_anonymous_path(v: &'static u8) -> ContainsLifetime<'static> { + | + +error: lifetime flowing from input to output with different syntax + --> $DIR/mismatched-lifetime-syntaxes.rs:136:38 + | +LL | fn static_ref_to_hidden_ref(&'static self) -> &u8 { + | ^^^^^^^ --- the elided lifetime gets resolved as `'static` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'static` + | +LL | fn static_ref_to_hidden_ref(&'static self) -> &'static u8 { + | +++++++ + +error: lifetime flowing from input to output with different syntax + --> $DIR/mismatched-lifetime-syntaxes.rs:141:41 + | +LL | fn static_ref_to_anonymous_ref(&'static self) -> &'_ u8 { + | ^^^^^^^ -- the elided lifetime gets resolved as `'static` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'static` + | +LL - fn static_ref_to_anonymous_ref(&'static self) -> &'_ u8 { +LL + fn static_ref_to_anonymous_ref(&'static self) -> &'static u8 { + | + +error: lifetime flowing from input to output with different syntax + --> $DIR/mismatched-lifetime-syntaxes.rs:146:39 + | +LL | fn static_ref_to_hidden_path(&'static self) -> ContainsLifetime { + | ^^^^^^^ ---------------- the elided lifetime gets resolved as `'static` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'static` + | +LL | fn static_ref_to_hidden_path(&'static self) -> ContainsLifetime<'static> { + | +++++++++ + +error: lifetime flowing from input to output with different syntax + --> $DIR/mismatched-lifetime-syntaxes.rs:151:42 + | +LL | fn static_ref_to_anonymous_path(&'static self) -> ContainsLifetime<'_> { + | ^^^^^^^ -- the elided lifetime gets resolved as `'static` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'static` + | +LL - fn static_ref_to_anonymous_path(&'static self) -> ContainsLifetime<'_> { +LL + fn static_ref_to_anonymous_path(&'static self) -> ContainsLifetime<'static> { + | + +error: lifetime flowing from input to output with different syntax + --> $DIR/mismatched-lifetime-syntaxes.rs:163:46 + | +LL | fn named_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + '_ { + | ^^ -- the elided lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL - fn named_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + '_ { +LL + fn named_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + 'a { + | + +error: lifetime flowing from input to output with different syntax + --> $DIR/mismatched-lifetime-syntaxes.rs:168:56 + | +LL | fn named_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'_> { + | ^^ -- the elided lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL - fn named_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'_> { +LL + fn named_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'a> { + | + +error: lifetime flowing from input to output with different syntax + --> $DIR/mismatched-lifetime-syntaxes.rs:173:63 + | +LL | fn named_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + '_ { + | ^^ -- the elided lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL - fn named_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + '_ { +LL + fn named_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + 'a { + | + +error: lifetime flowing from input to output with different syntax + --> $DIR/mismatched-lifetime-syntaxes.rs:179:29 + | +LL | v: ContainsLifetime<'a>, + | ^^ this lifetime flows to the output +LL | +LL | ) -> impl FnOnce() + use<'_> { + | -- the elided lifetime gets resolved as `'a` + | +help: one option is to consistently use `'a` + | +LL - ) -> impl FnOnce() + use<'_> { +LL + ) -> impl FnOnce() + use<'a> { + | + +error: lifetime flowing from input to output with different syntax + --> $DIR/mismatched-lifetime-syntaxes.rs:188:33 + | +LL | fn multiple_outputs<'a>(v: &'a u8) -> (&u8, &u8) { + | ^^ --- --- the elided lifetimes get resolved as `'a` + | | | + | | the elided lifetimes get resolved as `'a` + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL | fn multiple_outputs<'a>(v: &'a u8) -> (&'a u8, &'a u8) { + | ++ ++ + +error: aborting due to 30 previous errors + diff --git a/tests/ui/lint/elided-named-lifetimes/example-from-issue48686.stderr b/tests/ui/lint/elided-named-lifetimes/example-from-issue48686.stderr deleted file mode 100644 index 2d8c6e996439d..0000000000000 --- a/tests/ui/lint/elided-named-lifetimes/example-from-issue48686.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error: elided lifetime has a name - --> $DIR/example-from-issue48686.rs:6:50 - | -LL | pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 { - | ^ this elided lifetime gets resolved as `'static` - | -note: the lint level is defined here - --> $DIR/example-from-issue48686.rs:1:9 - | -LL | #![deny(elided_named_lifetimes)] - | ^^^^^^^^^^^^^^^^^^^^^^ -help: consider specifying it explicitly - | -LL | pub fn get_mut(&'static self, x: &mut u8) -> &'static mut u8 { - | +++++++ - -error: aborting due to 1 previous error - diff --git a/tests/ui/lint/elided-named-lifetimes/missing-lifetime-kind.rs b/tests/ui/lint/elided-named-lifetimes/missing-lifetime-kind.rs deleted file mode 100644 index 2f9083ed65f6e..0000000000000 --- a/tests/ui/lint/elided-named-lifetimes/missing-lifetime-kind.rs +++ /dev/null @@ -1,27 +0,0 @@ -#![deny(elided_named_lifetimes)] - -fn ampersand<'a>(x: &'a u8) -> &u8 { - //~^ ERROR elided lifetime has a name - x -} - -struct Brackets<'a>(&'a u8); - -fn brackets<'a>(x: &'a u8) -> Brackets { - //~^ ERROR elided lifetime has a name - Brackets(x) -} - -struct Comma<'a, T>(&'a T); - -fn comma<'a>(x: &'a u8) -> Comma { - //~^ ERROR elided lifetime has a name - Comma(x) -} - -fn underscore<'a>(x: &'a u8) -> &'_ u8 { - //~^ ERROR elided lifetime has a name - x -} - -fn main() {} diff --git a/tests/ui/lint/elided-named-lifetimes/missing-lifetime-kind.stderr b/tests/ui/lint/elided-named-lifetimes/missing-lifetime-kind.stderr deleted file mode 100644 index 249ae146b1675..0000000000000 --- a/tests/ui/lint/elided-named-lifetimes/missing-lifetime-kind.stderr +++ /dev/null @@ -1,40 +0,0 @@ -error: elided lifetime has a name - --> $DIR/missing-lifetime-kind.rs:3:32 - | -LL | fn ampersand<'a>(x: &'a u8) -> &u8 { - | -- ^ this elided lifetime gets resolved as `'a` - | | - | lifetime `'a` declared here - | -note: the lint level is defined here - --> $DIR/missing-lifetime-kind.rs:1:9 - | -LL | #![deny(elided_named_lifetimes)] - | ^^^^^^^^^^^^^^^^^^^^^^ - -error: elided lifetime has a name - --> $DIR/missing-lifetime-kind.rs:10:31 - | -LL | fn brackets<'a>(x: &'a u8) -> Brackets { - | -- ^^^^^^^^ this elided lifetime gets resolved as `'a` - | | - | lifetime `'a` declared here - -error: elided lifetime has a name - --> $DIR/missing-lifetime-kind.rs:17:33 - | -LL | fn comma<'a>(x: &'a u8) -> Comma { - | -- ^ this elided lifetime gets resolved as `'a` - | | - | lifetime `'a` declared here - -error: elided lifetime has a name - --> $DIR/missing-lifetime-kind.rs:22:34 - | -LL | fn underscore<'a>(x: &'a u8) -> &'_ u8 { - | -- ^^ this elided lifetime gets resolved as `'a` - | | - | lifetime `'a` declared here - -error: aborting due to 4 previous errors - diff --git a/tests/ui/lint/elided-named-lifetimes/not-tied-to-crate.rs b/tests/ui/lint/elided-named-lifetimes/not-tied-to-crate.rs deleted file mode 100644 index 4f9218130fbc1..0000000000000 --- a/tests/ui/lint/elided-named-lifetimes/not-tied-to-crate.rs +++ /dev/null @@ -1,17 +0,0 @@ -#![allow(elided_named_lifetimes)] - -#[warn(elided_named_lifetimes)] -mod foo { - fn bar(x: &'static u8) -> &u8 { - //~^ WARNING elided lifetime has a name - x - } - - #[deny(elided_named_lifetimes)] - fn baz(x: &'static u8) -> &u8 { - //~^ ERROR elided lifetime has a name - x - } -} - -fn main() {} diff --git a/tests/ui/lint/elided-named-lifetimes/not-tied-to-crate.stderr b/tests/ui/lint/elided-named-lifetimes/not-tied-to-crate.stderr deleted file mode 100644 index 3c01375d50191..0000000000000 --- a/tests/ui/lint/elided-named-lifetimes/not-tied-to-crate.stderr +++ /dev/null @@ -1,34 +0,0 @@ -warning: elided lifetime has a name - --> $DIR/not-tied-to-crate.rs:5:31 - | -LL | fn bar(x: &'static u8) -> &u8 { - | ^ this elided lifetime gets resolved as `'static` - | -note: the lint level is defined here - --> $DIR/not-tied-to-crate.rs:3:8 - | -LL | #[warn(elided_named_lifetimes)] - | ^^^^^^^^^^^^^^^^^^^^^^ -help: consider specifying it explicitly - | -LL | fn bar(x: &'static u8) -> &'static u8 { - | +++++++ - -error: elided lifetime has a name - --> $DIR/not-tied-to-crate.rs:11:31 - | -LL | fn baz(x: &'static u8) -> &u8 { - | ^ this elided lifetime gets resolved as `'static` - | -note: the lint level is defined here - --> $DIR/not-tied-to-crate.rs:10:12 - | -LL | #[deny(elided_named_lifetimes)] - | ^^^^^^^^^^^^^^^^^^^^^^ -help: consider specifying it explicitly - | -LL | fn baz(x: &'static u8) -> &'static u8 { - | +++++++ - -error: aborting due to 1 previous error; 1 warning emitted - diff --git a/tests/ui/lint/elided-named-lifetimes/static.stderr b/tests/ui/lint/elided-named-lifetimes/static.stderr deleted file mode 100644 index 7ad08dbf04baf..0000000000000 --- a/tests/ui/lint/elided-named-lifetimes/static.stderr +++ /dev/null @@ -1,52 +0,0 @@ -error: elided lifetime has a name - --> $DIR/static.rs:16:33 - | -LL | fn ampersand(x: &'static u8) -> &u8 { - | ^ this elided lifetime gets resolved as `'static` - | -note: the lint level is defined here - --> $DIR/static.rs:1:9 - | -LL | #![deny(elided_named_lifetimes)] - | ^^^^^^^^^^^^^^^^^^^^^^ -help: consider specifying it explicitly - | -LL | fn ampersand(x: &'static u8) -> &'static u8 { - | +++++++ - -error: elided lifetime has a name - --> $DIR/static.rs:23:32 - | -LL | fn brackets(x: &'static u8) -> Brackets { - | ^^^^^^^^ this elided lifetime gets resolved as `'static` - | -help: consider specifying it explicitly - | -LL | fn brackets(x: &'static u8) -> Brackets<'static> { - | +++++++++ - -error: elided lifetime has a name - --> $DIR/static.rs:30:34 - | -LL | fn comma(x: &'static u8) -> Comma { - | ^ this elided lifetime gets resolved as `'static` - | -help: consider specifying it explicitly - | -LL | fn comma(x: &'static u8) -> Comma<'static, u8> { - | ++++++++ - -error: elided lifetime has a name - --> $DIR/static.rs:35:35 - | -LL | fn underscore(x: &'static u8) -> &'_ u8 { - | ^^ this elided lifetime gets resolved as `'static` - | -help: consider specifying it explicitly - | -LL - fn underscore(x: &'static u8) -> &'_ u8 { -LL + fn underscore(x: &'static u8) -> &'static u8 { - | - -error: aborting due to 4 previous errors - 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 { diff --git a/tests/ui/object-lifetime/object-lifetime-default-elision.rs b/tests/ui/object-lifetime/object-lifetime-default-elision.rs index ede6af51174b2..f7c0261cfbb9c 100644 --- a/tests/ui/object-lifetime/object-lifetime-default-elision.rs +++ b/tests/ui/object-lifetime/object-lifetime-default-elision.rs @@ -46,8 +46,6 @@ fn load1(ss: &dyn SomeTrait) -> &dyn SomeTrait { } fn load2<'a>(ss: &'a dyn SomeTrait) -> &dyn SomeTrait { - //~^ WARNING elided lifetime has a name - // Same as `load1` but with an explicit name thrown in for fun. ss diff --git a/tests/ui/object-lifetime/object-lifetime-default-elision.stderr b/tests/ui/object-lifetime/object-lifetime-default-elision.stderr index b44a184c6848f..b59956879275a 100644 --- a/tests/ui/object-lifetime/object-lifetime-default-elision.stderr +++ b/tests/ui/object-lifetime/object-lifetime-default-elision.stderr @@ -1,15 +1,5 @@ -warning: elided lifetime has a name - --> $DIR/object-lifetime-default-elision.rs:48:40 - | -LL | fn load2<'a>(ss: &'a dyn SomeTrait) -> &dyn SomeTrait { - | -- ^ this elided lifetime gets resolved as `'a` - | | - | lifetime `'a` declared here - | - = note: `#[warn(elided_named_lifetimes)]` on by default - error: lifetime may not live long enough - --> $DIR/object-lifetime-default-elision.rs:73:5 + --> $DIR/object-lifetime-default-elision.rs:71:5 | LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait { | -- -- lifetime `'b` defined here @@ -21,5 +11,5 @@ LL | ss | = help: consider adding the following bound: `'a: 'b` -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/ui/self/elision/ignore-non-reference-lifetimes.rs b/tests/ui/self/elision/ignore-non-reference-lifetimes.rs index cedc6f0f9bc62..ecd669059ed3a 100644 --- a/tests/ui/self/elision/ignore-non-reference-lifetimes.rs +++ b/tests/ui/self/elision/ignore-non-reference-lifetimes.rs @@ -4,11 +4,11 @@ struct Foo<'a>(&'a str); impl<'b> Foo<'b> { fn a<'a>(self: Self, a: &'a str) -> &str { - //~^ WARNING elided lifetime has a name + //~^ WARNING lifetime flowing from input to output with different syntax a } fn b<'a>(self: Foo<'b>, a: &'a str) -> &str { - //~^ WARNING elided lifetime has a name + //~^ WARNING lifetime flowing from input to output with different syntax a } } diff --git a/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr b/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr index 4465dbae52989..e395c035526ed 100644 --- a/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr +++ b/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr @@ -1,16 +1,29 @@ -warning: elided lifetime has a name - --> $DIR/ignore-non-reference-lifetimes.rs:6:41 +warning: lifetime flowing from input to output with different syntax + --> $DIR/ignore-non-reference-lifetimes.rs:6:30 | LL | fn a<'a>(self: Self, a: &'a str) -> &str { - | -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a` + | ^^ ---- the elided lifetime gets resolved as `'a` + | | + | this lifetime flows to the output | - = note: `#[warn(elided_named_lifetimes)]` on by default + = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default +help: one option is to consistently use `'a` + | +LL | fn a<'a>(self: Self, a: &'a str) -> &'a str { + | ++ -warning: elided lifetime has a name - --> $DIR/ignore-non-reference-lifetimes.rs:10:44 +warning: lifetime flowing from input to output with different syntax + --> $DIR/ignore-non-reference-lifetimes.rs:10:33 | LL | fn b<'a>(self: Foo<'b>, a: &'a str) -> &str { - | -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a` + | ^^ ---- the elided lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL | fn b<'a>(self: Foo<'b>, a: &'a str) -> &'a str { + | ++ warning: 2 warnings emitted diff --git a/tests/ui/self/elision/lt-ref-self-async.fixed b/tests/ui/self/elision/lt-ref-self-async.fixed index aae94f7a6ccce..191610336de3f 100644 --- a/tests/ui/self/elision/lt-ref-self-async.fixed +++ b/tests/ui/self/elision/lt-ref-self-async.fixed @@ -1,6 +1,6 @@ //@ edition:2018 //@ run-rustfix -#![allow(non_snake_case, dead_code, elided_named_lifetimes)] +#![allow(non_snake_case, dead_code, mismatched_lifetime_syntaxes)] use std::pin::Pin; diff --git a/tests/ui/self/elision/lt-ref-self-async.rs b/tests/ui/self/elision/lt-ref-self-async.rs index 0c11b271c35a7..c910a5d6d7e87 100644 --- a/tests/ui/self/elision/lt-ref-self-async.rs +++ b/tests/ui/self/elision/lt-ref-self-async.rs @@ -1,6 +1,6 @@ //@ edition:2018 //@ run-rustfix -#![allow(non_snake_case, dead_code, elided_named_lifetimes)] +#![allow(non_snake_case, dead_code, mismatched_lifetime_syntaxes)] use std::pin::Pin; diff --git a/tests/ui/self/self_lifetime-async.rs b/tests/ui/self/self_lifetime-async.rs index fd6902071188c..f839ab03a6072 100644 --- a/tests/ui/self/self_lifetime-async.rs +++ b/tests/ui/self/self_lifetime-async.rs @@ -4,13 +4,13 @@ struct Foo<'a>(&'a ()); impl<'a> Foo<'a> { async fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 } - //~^ WARNING elided lifetime has a name + //~^ WARNING lifetime flowing from input to output with different syntax } type Alias = Foo<'static>; impl Alias { async fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg } - //~^ WARNING elided lifetime has a name + //~^ WARNING lifetime flowing from input to output with different syntax } fn main() {} diff --git a/tests/ui/self/self_lifetime-async.stderr b/tests/ui/self/self_lifetime-async.stderr index 32de3fd18c97f..e33d7a831405a 100644 --- a/tests/ui/self/self_lifetime-async.stderr +++ b/tests/ui/self/self_lifetime-async.stderr @@ -1,18 +1,29 @@ -warning: elided lifetime has a name - --> $DIR/self_lifetime-async.rs:6:44 +warning: lifetime flowing from input to output with different syntax + --> $DIR/self_lifetime-async.rs:6:29 | LL | async fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 } - | -- ^ this elided lifetime gets resolved as `'b` - | | - | lifetime `'b` declared here + | ^^ --- the elided lifetime gets resolved as `'b` + | | + | this lifetime flows to the output | - = note: `#[warn(elided_named_lifetimes)]` on by default + = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default +help: one option is to consistently use `'b` + | +LL | async fn foo<'b>(self: &'b Foo<'a>) -> &'b () { self.0 } + | ++ -warning: elided lifetime has a name - --> $DIR/self_lifetime-async.rs:12:52 +warning: lifetime flowing from input to output with different syntax + --> $DIR/self_lifetime-async.rs:12:42 | LL | async fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg } - | -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a` + | ^^ --- the elided lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL | async fn bar<'a>(self: &Alias, arg: &'a ()) -> &'a () { arg } + | ++ warning: 2 warnings emitted diff --git a/tests/ui/self/self_lifetime.rs b/tests/ui/self/self_lifetime.rs index 0607c3b9317f1..aaa31f85ad5b0 100644 --- a/tests/ui/self/self_lifetime.rs +++ b/tests/ui/self/self_lifetime.rs @@ -5,13 +5,13 @@ struct Foo<'a>(&'a ()); impl<'a> Foo<'a> { fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 } - //~^ WARNING elided lifetime has a name + //~^ WARNING lifetime flowing from input to output with different syntax } type Alias = Foo<'static>; impl Alias { fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg } - //~^ WARNING elided lifetime has a name + //~^ WARNING lifetime flowing from input to output with different syntax } fn main() {} diff --git a/tests/ui/self/self_lifetime.stderr b/tests/ui/self/self_lifetime.stderr index cd8f4d8adf8b1..895978e9c0c2f 100644 --- a/tests/ui/self/self_lifetime.stderr +++ b/tests/ui/self/self_lifetime.stderr @@ -1,18 +1,29 @@ -warning: elided lifetime has a name - --> $DIR/self_lifetime.rs:7:38 +warning: lifetime flowing from input to output with different syntax + --> $DIR/self_lifetime.rs:7:23 | LL | fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 } - | -- ^ this elided lifetime gets resolved as `'b` - | | - | lifetime `'b` declared here + | ^^ --- the elided lifetime gets resolved as `'b` + | | + | this lifetime flows to the output | - = note: `#[warn(elided_named_lifetimes)]` on by default + = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default +help: one option is to consistently use `'b` + | +LL | fn foo<'b>(self: &'b Foo<'a>) -> &'b () { self.0 } + | ++ -warning: elided lifetime has a name - --> $DIR/self_lifetime.rs:13:46 +warning: lifetime flowing from input to output with different syntax + --> $DIR/self_lifetime.rs:13:36 | LL | fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg } - | -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a` + | ^^ --- the elided lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL | fn bar<'a>(self: &Alias, arg: &'a ()) -> &'a () { arg } + | ++ warning: 2 warnings emitted diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr index b369af62f8760..4be3d3fd3b568 100644 --- a/tests/ui/stats/input-stats.stderr +++ b/tests/ui/stats/input-stats.stderr @@ -150,29 +150,29 @@ hir-stats Pat 360 ( 4.0%) 5 72 hir-stats - Struct 72 ( 0.8%) 1 hir-stats - Wild 72 ( 0.8%) 1 hir-stats - Binding 216 ( 2.4%) 3 -hir-stats GenericParam 400 ( 4.5%) 5 80 -hir-stats Generics 560 ( 6.2%) 10 56 -hir-stats Ty 720 ( 8.0%) 15 48 -hir-stats - Ptr 48 ( 0.5%) 1 -hir-stats - Ref 48 ( 0.5%) 1 -hir-stats - Path 624 ( 6.9%) 13 -hir-stats Expr 768 ( 8.5%) 12 64 +hir-stats GenericParam 400 ( 4.4%) 5 80 +hir-stats Generics 560 ( 6.1%) 10 56 +hir-stats Expr 768 ( 8.4%) 12 64 hir-stats - InlineAsm 64 ( 0.7%) 1 hir-stats - Match 64 ( 0.7%) 1 hir-stats - Path 64 ( 0.7%) 1 hir-stats - Struct 64 ( 0.7%) 1 hir-stats - Lit 128 ( 1.4%) 2 -hir-stats - Block 384 ( 4.3%) 6 -hir-stats Item 968 (10.8%) 11 88 +hir-stats - Block 384 ( 4.2%) 6 +hir-stats Ty 840 ( 9.2%) 15 56 +hir-stats - Ptr 56 ( 0.6%) 1 +hir-stats - Ref 56 ( 0.6%) 1 +hir-stats - Path 728 ( 8.0%) 13 +hir-stats Item 968 (10.6%) 11 88 hir-stats - Enum 88 ( 1.0%) 1 hir-stats - ExternCrate 88 ( 1.0%) 1 hir-stats - ForeignMod 88 ( 1.0%) 1 hir-stats - Impl 88 ( 1.0%) 1 hir-stats - Trait 88 ( 1.0%) 1 -hir-stats - Fn 176 ( 2.0%) 2 +hir-stats - Fn 176 ( 1.9%) 2 hir-stats - Use 352 ( 3.9%) 4 -hir-stats Path 1_240 (13.8%) 31 40 -hir-stats PathSegment 1_920 (21.4%) 40 48 +hir-stats Path 1_240 (13.6%) 31 40 +hir-stats PathSegment 1_920 (21.1%) 40 48 hir-stats ---------------------------------------------------------------- -hir-stats Total 8_988 180 +hir-stats Total 9_108 180 hir-stats diff --git a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.rs b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.rs index 443a7e3835e3e..a4efd1e69b0ba 100644 --- a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.rs +++ b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.rs @@ -62,7 +62,6 @@ mod in_path { // This must not err, as the `&` actually resolves to `'a`. fn resolved_anonymous<'a, T: 'a>(f: impl Fn(&'a str) -> &T) { - //~^ WARNING elided lifetime has a name f("f"); } diff --git a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr index 24013c85c8758..c001c40fb9f33 100644 --- a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr +++ b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr @@ -128,14 +128,6 @@ LL - fn g(mut x: impl Foo<()>) -> Option<&()> { x.next() } LL + fn g(mut x: impl Foo<()>) -> Option<()> { x.next() } | -warning: elided lifetime has a name - --> $DIR/impl-trait-missing-lifetime-gated.rs:64:57 - | -LL | fn resolved_anonymous<'a, T: 'a>(f: impl Fn(&'a str) -> &T) { - | -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a` - | - = note: `#[warn(elided_named_lifetimes)]` on by default - error[E0658]: anonymous lifetimes in `impl Trait` are unstable --> $DIR/impl-trait-missing-lifetime-gated.rs:6:35 | @@ -242,7 +234,7 @@ help: consider introducing a named lifetime parameter LL | fn g<'a>(mut x: impl Foo<'a, ()>) -> Option<&()> { x.next() } | ++++ +++ -error: aborting due to 14 previous errors; 1 warning emitted +error: aborting due to 14 previous errors Some errors have detailed explanations: E0106, E0658. For more information about an error, try `rustc --explain E0106`. diff --git a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs index b61bea16e3bc8..b641f5941dcef 100644 --- a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs +++ b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs @@ -100,7 +100,6 @@ where // This also works. The `'_` isn't necessary but it's where we arrive to following the suggestions: fn ok2<'a, G: 'a, T>(g: G, dest: &'a mut T) -> impl FnOnce() + '_ + 'a -//~^ WARNING elided lifetime has a name where G: Get, { diff --git a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index b92719e8033a0..41cb2ee46bb5a 100644 --- a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -6,14 +6,6 @@ LL | fn baz(g: G, dest: &mut T) -> impl FnOnce() + '_ | | | help: consider introducing lifetime `'a` here: `'a,` -warning: elided lifetime has a name - --> $DIR/missing-lifetimes-in-signature.rs:102:64 - | -LL | fn ok2<'a, G: 'a, T>(g: G, dest: &'a mut T) -> impl FnOnce() + '_ + 'a - | -- lifetime `'a` declared here ^^ this elided lifetime gets resolved as `'a` - | - = note: `#[warn(elided_named_lifetimes)]` on by default - error[E0700]: hidden type for `impl FnOnce()` captures lifetime that does not appear in bounds --> $DIR/missing-lifetimes-in-signature.rs:19:5 | @@ -136,7 +128,7 @@ help: consider adding an explicit lifetime bound LL | G: Get + 'a, | ++++ -error: aborting due to 8 previous errors; 1 warning emitted +error: aborting due to 8 previous errors Some errors have detailed explanations: E0261, E0309, E0311, E0621, E0700. For more information about an error, try `rustc --explain E0261`. diff --git a/tests/ui/type-alias-impl-trait/missing_lifetime_bound.rs b/tests/ui/type-alias-impl-trait/missing_lifetime_bound.rs index d77efa39aeb61..60d9521621fac 100644 --- a/tests/ui/type-alias-impl-trait/missing_lifetime_bound.rs +++ b/tests/ui/type-alias-impl-trait/missing_lifetime_bound.rs @@ -3,7 +3,7 @@ type Opaque2 = impl Sized; type Opaque<'a, T> = Opaque2; #[define_opaque(Opaque)] -fn defining<'a, T>(x: &'a i32) -> Opaque { x } //~ WARNING elided lifetime has a name +fn defining<'a, T>(x: &'a i32) -> Opaque { x } //~^ ERROR: hidden type for `Opaque2` captures lifetime that does not appear in bounds fn main() {} diff --git a/tests/ui/type-alias-impl-trait/missing_lifetime_bound.stderr b/tests/ui/type-alias-impl-trait/missing_lifetime_bound.stderr index 61eb76ffc5ae2..b73e6b8c1015b 100644 --- a/tests/ui/type-alias-impl-trait/missing_lifetime_bound.stderr +++ b/tests/ui/type-alias-impl-trait/missing_lifetime_bound.stderr @@ -1,13 +1,3 @@ -warning: elided lifetime has a name - --> $DIR/missing_lifetime_bound.rs:6:41 - | -LL | fn defining<'a, T>(x: &'a i32) -> Opaque { x } - | -- ^ this elided lifetime gets resolved as `'a` - | | - | lifetime `'a` declared here - | - = note: `#[warn(elided_named_lifetimes)]` on by default - error[E0700]: hidden type for `Opaque2` captures lifetime that does not appear in bounds --> $DIR/missing_lifetime_bound.rs:6:47 | @@ -19,6 +9,6 @@ LL | fn defining<'a, T>(x: &'a i32) -> Opaque { x } | | | hidden type `&'a i32` captures the lifetime `'a` as defined here -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/underscore-lifetimes.rs b/tests/ui/underscore-lifetimes.rs index 6174f8ce036fa..a372851f9cfff 100644 --- a/tests/ui/underscore-lifetimes.rs +++ b/tests/ui/underscore-lifetimes.rs @@ -1,6 +1,6 @@ //@ run-pass -#![allow(dead_code)] +#![allow(dead_code, mismatched_lifetime_syntaxes)] struct Foo<'a>(&'a u8); fn foo(x: &u8) -> Foo<'_> {