diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index d8b55bea3d763..86713a25fdc97 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; @@ -1868,7 +1868,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, @@ -1901,7 +1902,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 b1d1c35e64a1d..b15361bdc1e74 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -54,8 +54,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, }; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_macros::extension; @@ -1079,7 +1079,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` @@ -1198,35 +1202,11 @@ 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() }; @@ -1302,7 +1282,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 } @@ -1393,6 +1377,31 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.lower_node_id(t.id) } } + 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 = /// impl Trait`): this creates the associated Opaque Type (TAIT) definition and then returns a /// HIR type that references the TAIT. @@ -1474,9 +1483,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!(); @@ -1739,9 +1748,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), @@ -1749,12 +1760,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))] @@ -1763,7 +1790,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); @@ -1788,17 +1816,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, )) } @@ -2390,7 +2414,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 0bd65aec10f49..be8754e682b3a 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}; use rustc_middle::span_bug; use rustc_session::parse::add_feature_diagnostics; use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym}; @@ -433,23 +432,27 @@ 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..end).map(|id| { - 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_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index c2b1dff4cf1f7..d14ad8f40144c 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}; @@ -684,13 +684,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 bd13c413a4df4..8a48feea191fc 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 75bb0e8e7b43f..c0c5dba46772a 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 9372ab532bf3a..dbbb378c90732 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -850,12 +850,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 6455f33b9d153..88e74dfba5ac3 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:?}") + } } } } diff --git a/compiler/rustc_hir/src/hir/tests.rs b/compiler/rustc_hir/src/hir/tests.rs index 62ef02d2f500c..997273af29327 100644 --- a/compiler/rustc_hir/src/hir/tests.rs +++ b/compiler/rustc_hir/src/hir/tests.rs @@ -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 dfaa374592bc2..9e7305430e5f5 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..667758f7b4a96 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 @@ -508,6 +503,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/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 40ca9e05d95d6..c59987cabb782 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -10,11 +10,11 @@ use rustc_errors::{ 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; @@ -450,16 +450,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 1789a2970d62a..5faff358ee43a 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -56,6 +56,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; @@ -96,6 +97,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::*; @@ -245,6 +247,7 @@ late_lint_methods!( IfLetRescope: IfLetRescope::default(), StaticMutRefs: StaticMutRefs, UnqualifiedLocalImports: UnqualifiedLocalImports, + LifetimeStyle: LifetimeStyle, ] ] ); @@ -352,6 +355,7 @@ 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"); // 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..858f4b6810bb4 --- /dev/null +++ b/compiler/rustc_lint/src/lifetime_style.rs @@ -0,0 +1,301 @@ +use rustc_data_structures::fx::FxIndexMap; +use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::{self as hir, LifetimeSource, LifetimeSyntax}; +use rustc_session::{declare_lint, declare_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_pass!(LifetimeStyle => [MISMATCHED_LIFETIME_SYNTAXES]); + +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); + } +} + +#[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, + } +} + +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; + } +} diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 51214c8e8a4cf..a004361e3c0a1 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -6,19 +6,19 @@ use rustc_abi::ExternAbi; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString, ElidedLifetimeInPathSubdiag, - EmissionGuarantee, LintDiagnostic, MultiSpan, SubdiagMessageOp, Subdiagnostic, SuggestionStyle, + 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); @@ -2697,58 +2669,6 @@ pub(crate) struct ElidedLifetimesInPaths { 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 +3104,95 @@ 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), + ); + } + } + } +} diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index b25d2a30681c0..c26dd16414680 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -40,7 +40,6 @@ declare_lint_pass! { 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, @@ -1827,38 +1826,6 @@ declare_lint! { "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..997a4f468f62d 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)] @@ -653,10 +647,6 @@ pub enum BuiltinLintDiag { }, 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 85eddafefcd56..995fc85676e84 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}; @@ -1852,11 +1852,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 bae2fdeecafcc..42d761acf346c 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; @@ -2197,47 +2196,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 +2713,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 +2752,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 d4fe446cc9f76..6e70fb8308480 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -3276,7 +3276,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 { @@ -3288,7 +3288,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 4e5581fb1da0d..1063115ed237f 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 e4ab78b62477f..84e7686fdd3fc 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/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/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/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/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/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<'_> {