From 1326e66e3c05995304dcd00c023d4f532a4d0330 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 31 Oct 2021 17:11:28 +0100 Subject: [PATCH 1/7] Move report_elision_failure in diagnostics.rs. --- .../rustc_resolve/src/late/diagnostics.rs | 78 +++++++++++++++++ compiler/rustc_resolve/src/late/lifetimes.rs | 86 +------------------ 2 files changed, 82 insertions(+), 82 deletions(-) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index d506931b516e7..d410fafba2351 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1871,6 +1871,84 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { err.emit(); } + crate fn report_elision_failure( + &mut self, + db: &mut DiagnosticBuilder<'_>, + params: &[ElisionFailureInfo], + ) -> bool /* add `'static` lifetime to lifetime list */ { + let mut m = String::new(); + let len = params.len(); + + let elided_params: Vec<_> = + params.iter().cloned().filter(|info| info.lifetime_count > 0).collect(); + + let elided_len = elided_params.len(); + + for (i, info) in elided_params.into_iter().enumerate() { + let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions, span } = + info; + + db.span_label(span, ""); + let help_name = if let Some(ident) = + parent.and_then(|body| self.tcx.hir().body(body).params[index].pat.simple_ident()) + { + format!("`{}`", ident) + } else { + format!("argument {}", index + 1) + }; + + m.push_str( + &(if n == 1 { + help_name + } else { + format!( + "one of {}'s {} {}lifetimes", + help_name, + n, + if have_bound_regions { "free " } else { "" } + ) + })[..], + ); + + if elided_len == 2 && i == 0 { + m.push_str(" or "); + } else if i + 2 == elided_len { + m.push_str(", or "); + } else if i != elided_len - 1 { + m.push_str(", "); + } + } + + if len == 0 { + db.help( + "this function's return type contains a borrowed value, \ + but there is no value for it to be borrowed from", + ); + true + } else if elided_len == 0 { + db.help( + "this function's return type contains a borrowed value with \ + an elided lifetime, but the lifetime cannot be derived from \ + the arguments", + ); + true + } else if elided_len == 1 { + db.help(&format!( + "this function's return type contains a borrowed value, \ + but the signature does not say which {} it is borrowed from", + m + )); + false + } else { + db.help(&format!( + "this function's return type contains a borrowed value, \ + but the signature does not say whether it is borrowed from {}", + m + )); + false + } + } + // FIXME(const_generics): This patches over an ICE caused by non-'static lifetimes in const // generics. We are disallowing this until we can decide on how we want to handle non-'static // lifetimes in const generics. See issue #74052 for discussion. diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 39e710cb77f3f..db6eacfe9510b 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -357,11 +357,11 @@ enum Elide { #[derive(Clone, Debug)] crate struct ElisionFailureInfo { /// Where we can find the argument pattern. - parent: Option, + crate parent: Option, /// The index of the argument in the original definition. - index: usize, - lifetime_count: usize, - have_bound_regions: bool, + crate index: usize, + crate lifetime_count: usize, + crate have_bound_regions: bool, crate span: Span, } @@ -3166,84 +3166,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { err.emit(); } - fn report_elision_failure( - &mut self, - db: &mut DiagnosticBuilder<'_>, - params: &[ElisionFailureInfo], - ) -> bool /* add `'static` lifetime to lifetime list */ { - let mut m = String::new(); - let len = params.len(); - - let elided_params: Vec<_> = - params.iter().cloned().filter(|info| info.lifetime_count > 0).collect(); - - let elided_len = elided_params.len(); - - for (i, info) in elided_params.into_iter().enumerate() { - let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions, span } = - info; - - db.span_label(span, ""); - let help_name = if let Some(ident) = - parent.and_then(|body| self.tcx.hir().body(body).params[index].pat.simple_ident()) - { - format!("`{}`", ident) - } else { - format!("argument {}", index + 1) - }; - - m.push_str( - &(if n == 1 { - help_name - } else { - format!( - "one of {}'s {} {}lifetimes", - help_name, - n, - if have_bound_regions { "free " } else { "" } - ) - })[..], - ); - - if elided_len == 2 && i == 0 { - m.push_str(" or "); - } else if i + 2 == elided_len { - m.push_str(", or "); - } else if i != elided_len - 1 { - m.push_str(", "); - } - } - - if len == 0 { - db.help( - "this function's return type contains a borrowed value, \ - but there is no value for it to be borrowed from", - ); - true - } else if elided_len == 0 { - db.help( - "this function's return type contains a borrowed value with \ - an elided lifetime, but the lifetime cannot be derived from \ - the arguments", - ); - true - } else if elided_len == 1 { - db.help(&format!( - "this function's return type contains a borrowed value, \ - but the signature does not say which {} it is borrowed from", - m - )); - false - } else { - db.help(&format!( - "this function's return type contains a borrowed value, \ - but the signature does not say whether it is borrowed from {}", - m - )); - false - } - } - fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime) { debug!("resolve_object_lifetime_default(lifetime_ref={:?})", lifetime_ref); let mut late_depth = 0; From 2752991add45afb3fc5d3e92479d35d178984236 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 31 Oct 2021 17:21:32 +0100 Subject: [PATCH 2/7] Flatten match. --- compiler/rustc_resolve/src/late/lifetimes.rs | 78 ++++++++++---------- 1 file changed, 41 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index db6eacfe9510b..9410897cb0371 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -3076,50 +3076,54 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { scope = s; } - Scope::Elision { ref elide, ref s, .. } => { - let lifetime = match *elide { - Elide::FreshLateAnon(named_late_bound_vars, ref counter) => { - for lifetime_ref in lifetime_refs { - let lifetime = Region::late_anon(named_late_bound_vars, counter) - .shifted(late_depth); - - self.insert_lifetime(lifetime_ref, lifetime); - } - return; - } - Elide::Exact(l) => l.shifted(late_depth), - Elide::Error(ref e) => { - let mut scope = s; - loop { - match scope { - Scope::Binder { ref lifetimes, s, .. } => { - // Collect named lifetimes for suggestions. - for name in lifetimes.keys() { - if let hir::ParamName::Plain(name) = name { - lifetime_names.insert(name.name); - lifetime_spans.push(name.span); - } - } - scope = s; - } - Scope::ObjectLifetimeDefault { ref s, .. } - | Scope::Elision { ref s, .. } - | Scope::TraitRefBoundary { ref s, .. } => { - scope = s; + Scope::Elision { + elide: Elide::FreshLateAnon(named_late_bound_vars, ref counter), + .. + } => { + for lifetime_ref in lifetime_refs { + let lifetime = + Region::late_anon(named_late_bound_vars, counter).shifted(late_depth); + + self.insert_lifetime(lifetime_ref, lifetime); + } + return; + } + + Scope::Elision { elide: Elide::Exact(l), .. } => { + let lifetime = l.shifted(late_depth); + for lifetime_ref in lifetime_refs { + self.insert_lifetime(lifetime_ref, lifetime); + } + return; + } + + Scope::Elision { elide: Elide::Error(ref e), ref s, .. } => { + let mut scope = s; + loop { + match scope { + Scope::Binder { ref lifetimes, s, .. } => { + // Collect named lifetimes for suggestions. + for name in lifetimes.keys() { + if let hir::ParamName::Plain(name) = name { + lifetime_names.insert(name.name); + lifetime_spans.push(name.span); } - _ => break, } + scope = s; } - break Some(&e[..]); + Scope::ObjectLifetimeDefault { ref s, .. } + | Scope::Elision { ref s, .. } + | Scope::TraitRefBoundary { ref s, .. } => { + scope = s; + } + _ => break, } - Elide::Forbid => break None, - }; - for lifetime_ref in lifetime_refs { - self.insert_lifetime(lifetime_ref, lifetime); } - return; + break Some(&e[..]); } + Scope::Elision { elide: Elide::Forbid, .. } => break None, + Scope::ObjectLifetimeDefault { s, .. } | Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } => { From 2560c76b12fb53a548a5c9fe5d33eb4da19c2f8e Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 11 Jul 2021 15:04:57 +0200 Subject: [PATCH 3/7] Lint elided lifetimes in path during lifetime resolution. --- compiler/rustc_ast_lowering/src/lib.rs | 17 ++++-- compiler/rustc_ast_lowering/src/path.rs | 22 +------ .../src/diagnostics/region_name.rs | 4 +- compiler/rustc_hir/src/hir.rs | 5 ++ compiler/rustc_hir/src/intravisit.rs | 1 + .../rustc_resolve/src/late/diagnostics.rs | 40 ++++++++++++- compiler/rustc_resolve/src/late/lifetimes.rs | 26 +++++--- .../in-band-lifetimes/elided-lifetimes.fixed | 31 ++++++---- .../ui/in-band-lifetimes/elided-lifetimes.rs | 31 ++++++---- .../in-band-lifetimes/elided-lifetimes.stderr | 60 ++++++++++++++----- .../force-warn/allowed-by-default-lint.stderr | 6 +- src/test/ui/lint/reasons.rs | 4 +- src/test/ui/lint/reasons.stderr | 12 ++-- 13 files changed, 181 insertions(+), 78 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 2b3a538772ecb..a561475c76a0b 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1928,6 +1928,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let param_name = match lt.name { hir::LifetimeName::Param(param_name) => param_name, hir::LifetimeName::Implicit + | hir::LifetimeName::ImplicitMissing | hir::LifetimeName::Underscore | hir::LifetimeName::Static => hir::ParamName::Plain(lt.name.ident()), hir::LifetimeName::ImplicitObjectLifetimeDefault => { @@ -2322,11 +2323,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &'s mut self, span: Span, count: usize, + param_mode: ParamMode, ) -> impl Iterator + Captures<'a> + Captures<'s> + Captures<'hir> { - (0..count).map(move |_| self.elided_path_lifetime(span)) + (0..count).map(move |_| self.elided_path_lifetime(span, param_mode)) } - fn elided_path_lifetime(&mut self, span: Span) -> hir::Lifetime { + fn elided_path_lifetime(&mut self, span: Span, param_mode: ParamMode) -> hir::Lifetime { match self.anonymous_lifetime_mode { AnonymousLifetimeMode::CreateParameter => { // We should have emitted E0726 when processing this path above @@ -2342,7 +2344,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // lifetime. Instead, we simply create an implicit lifetime, which will be checked // later, at which point a suitable error will be emitted. AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => { - self.new_implicit_lifetime(span) + if param_mode == ParamMode::Explicit { + let id = self.resolver.next_node_id(); + self.new_named_lifetime(id, span, hir::LifetimeName::ImplicitMissing) + } else { + self.new_implicit_lifetime(span) + } } } } @@ -2536,7 +2543,9 @@ fn lifetimes_from_impl_trait_bounds( fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) { let name = match lifetime.name { - hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => { + hir::LifetimeName::Implicit + | hir::LifetimeName::ImplicitMissing + | hir::LifetimeName::Underscore => { if self.collect_elided_lifetimes { // Use `'_` for both implicit and underscore lifetimes in // `type Foo<'_> = impl SomeTrait<'_>;`. diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 929f427484dba..ab87867bb0388 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -7,8 +7,6 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, PartialRes, Res}; use rustc_hir::def_id::DefId; use rustc_hir::GenericArg; -use rustc_session::lint::builtin::ELIDED_LIFETIMES_IN_PATHS; -use rustc_session::lint::BuiltinLintDiagnostics; use rustc_span::symbol::Ident; use rustc_span::{BytePos, Span, DUMMY_SP}; @@ -275,7 +273,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // See rustc_resolve::late::lifetimes::LifetimeContext::add_missing_lifetime_specifiers_label let elided_lifetime_span = if generic_args.span.is_empty() { // If there are no brackets, use the identifier span. - segment.ident.span + path_span } 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)) @@ -284,7 +282,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo() }; generic_args.args = self - .elided_path_lifetimes(elided_lifetime_span, expected_lifetimes) + .elided_path_lifetimes(elided_lifetime_span, expected_lifetimes, param_mode) .map(GenericArg::Lifetime) .chain(generic_args.args.into_iter()) .collect(); @@ -329,21 +327,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { err.note("assuming a `'static` lifetime..."); err.emit(); } - AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => { - self.resolver.lint_buffer().buffer_lint_with_diagnostic( - ELIDED_LIFETIMES_IN_PATHS, - CRATE_NODE_ID, - path_span, - "hidden lifetime parameters in types are deprecated", - BuiltinLintDiagnostics::ElidedLifetimesInPaths( - expected_lifetimes, - path_span, - incl_angl_brckt, - insertion_sp, - suggestion, - ), - ); - } + AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => {} } } } diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 5edb52b0b650d..64df452c73978 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -584,7 +584,9 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span)) } - hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit => { + hir::LifetimeName::ImplicitObjectLifetimeDefault + | hir::LifetimeName::Implicit + | hir::LifetimeName::ImplicitMissing => { // In this case, the user left off the lifetime; so // they wrote something like: // diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index c67d3df3dedd8..707861f562d91 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -94,6 +94,9 @@ pub enum LifetimeName { /// User wrote nothing (e.g., the lifetime in `&u32`). Implicit, + /// User wrote nothing and should have. + ImplicitMissing, + /// Implicit lifetime in a context like `dyn Foo`. This is /// distinguished from implicit lifetimes elsewhere because the /// lifetime that they default to must appear elsewhere within the @@ -123,6 +126,7 @@ impl LifetimeName { match *self { LifetimeName::ImplicitObjectLifetimeDefault | LifetimeName::Implicit + | LifetimeName::ImplicitMissing | LifetimeName::Error => Ident::empty(), LifetimeName::Underscore => Ident::with_dummy_span(kw::UnderscoreLifetime), LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime), @@ -134,6 +138,7 @@ impl LifetimeName { match self { LifetimeName::ImplicitObjectLifetimeDefault | LifetimeName::Implicit + | LifetimeName::ImplicitMissing | LifetimeName::Underscore => true, // It might seem surprising that `Fresh(_)` counts as diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index cff543760f42a..5f8e4ba2d1398 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -546,6 +546,7 @@ pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime | LifetimeName::Static | LifetimeName::Error | LifetimeName::Implicit + | LifetimeName::ImplicitMissing | LifetimeName::ImplicitObjectLifetimeDefault | LifetimeName::Underscore => {} } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index d410fafba2351..2b032847c6a7f 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1949,6 +1949,41 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { } } + crate fn report_elided_lifetime_in_ty(&self, lifetime_refs: &[&hir::Lifetime]) { + let missing_lifetimes = lifetime_refs + .iter() + .filter(|a| matches!(a, hir::Lifetime { name: hir::LifetimeName::ImplicitMissing, .. })) + .count(); + + if missing_lifetimes > 0 { + let mut spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect(); + spans.sort(); + let mut spans_dedup = spans.clone(); + spans_dedup.dedup(); + let spans_with_counts: Vec<_> = spans_dedup + .into_iter() + .map(|sp| (sp, spans.iter().filter(|nsp| *nsp == &sp).count())) + .collect(); + + self.tcx.struct_span_lint_hir( + rustc_session::lint::builtin::ELIDED_LIFETIMES_IN_PATHS, + hir::CRATE_HIR_ID, + spans, + |lint| { + let mut db = lint.build("hidden lifetime parameters in types are deprecated"); + self.add_missing_lifetime_specifiers_label( + &mut db, + spans_with_counts, + &FxHashSet::from_iter([kw::UnderscoreLifetime]), + Vec::new(), + &[], + ); + db.emit() + }, + ); + } + } + // FIXME(const_generics): This patches over an ICE caused by non-'static lifetimes in const // generics. We are disallowing this until we can decide on how we want to handle non-'static // lifetimes in const generics. See issue #74052 for discussion. @@ -2375,7 +2410,10 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { ); let is_allowed_lifetime = matches!( lifetime_ref.name, - hir::LifetimeName::Implicit | hir::LifetimeName::Static | hir::LifetimeName::Underscore + hir::LifetimeName::Implicit + | hir::LifetimeName::ImplicitMissing + | hir::LifetimeName::Static + | hir::LifetimeName::Underscore ); if !self.tcx.lazy_normalization() && is_anon_const && !is_allowed_lifetime { diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 9410897cb0371..0de6b8695ca3b 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -923,7 +923,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } }); match lifetime.name { - LifetimeName::Implicit => { + LifetimeName::Implicit | hir::LifetimeName::ImplicitMissing => { // For types like `dyn Foo`, we should // generate a special form of elided. span_bug!(ty.span, "object-lifetime-default expected, not implicit",); @@ -3057,9 +3057,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let error = loop { match *scope { // Do not assign any resolution, it will be inferred. - Scope::Body { .. } => return, + Scope::Body { .. } => break Ok(()), - Scope::Root => break None, + Scope::Root => break Err(None), Scope::Binder { s, ref lifetimes, scope_type, .. } => { // collect named lifetimes for suggestions @@ -3086,7 +3086,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { self.insert_lifetime(lifetime_ref, lifetime); } - return; + break Ok(()); } Scope::Elision { elide: Elide::Exact(l), .. } => { @@ -3094,7 +3094,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { for lifetime_ref in lifetime_refs { self.insert_lifetime(lifetime_ref, lifetime); } - return; + break Ok(()); } Scope::Elision { elide: Elide::Error(ref e), ref s, .. } => { @@ -3119,10 +3119,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { _ => break, } } - break Some(&e[..]); + break Err(Some(&e[..])); } - Scope::Elision { elide: Elide::Forbid, .. } => break None, + Scope::Elision { elide: Elide::Forbid, .. } => break Err(None), Scope::ObjectLifetimeDefault { s, .. } | Scope::Supertrait { s, .. } @@ -3132,6 +3132,14 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } }; + let error = match error { + Ok(()) => { + self.report_elided_lifetime_in_ty(lifetime_refs); + return; + } + Err(error) => error, + }; + // If we specifically need the `scope_for_path` map, then we're in the // diagnostic pass and we don't want to emit more errors. if self.map.scope_for_path.is_some() { @@ -3274,7 +3282,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { )) .emit(); } - hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit => { + hir::LifetimeName::Param(_) + | hir::LifetimeName::Implicit + | hir::LifetimeName::ImplicitMissing => { self.resolve_lifetime_ref(lt); } hir::LifetimeName::ImplicitObjectLifetimeDefault => { diff --git a/src/test/ui/in-band-lifetimes/elided-lifetimes.fixed b/src/test/ui/in-band-lifetimes/elided-lifetimes.fixed index 2998f05efbae4..ca70242ef3d67 100644 --- a/src/test/ui/in-band-lifetimes/elided-lifetimes.fixed +++ b/src/test/ui/in-band-lifetimes/elided-lifetimes.fixed @@ -5,23 +5,24 @@ #![deny(elided_lifetimes_in_paths)] //~^ NOTE the lint level is defined here -use std::cell::{RefCell, Ref}; +use std::cell::{Ref, RefCell}; - -struct Foo<'a> { x: &'a u32 } +struct Foo<'a> { + x: &'a u32, +} fn foo(x: &Foo<'_>) { //~^ ERROR hidden lifetime parameters in types are deprecated - //~| HELP indicate the anonymous lifetime + //~| NOTE expected named lifetime parameter + //~| HELP consider using the `'_` lifetime } fn bar(x: &Foo<'_>) {} - struct Wrapped<'a>(&'a str); struct WrappedWithBow<'a> { - gift: &'a str + gift: &'a str, } struct MatchedSet<'a, 'b> { @@ -31,19 +32,22 @@ struct MatchedSet<'a, 'b> { fn wrap_gift(gift: &str) -> Wrapped<'_> { //~^ ERROR hidden lifetime parameters in types are deprecated - //~| HELP indicate the anonymous lifetime + //~| NOTE expected named lifetime parameter + //~| HELP consider using the `'_` lifetime Wrapped(gift) } fn wrap_gift_with_bow(gift: &str) -> WrappedWithBow<'_> { //~^ ERROR hidden lifetime parameters in types are deprecated - //~| HELP indicate the anonymous lifetime + //~| NOTE expected named lifetime parameter + //~| HELP consider using the `'_` lifetime WrappedWithBow { gift } } fn inspect_matched_set(set: MatchedSet<'_, '_>) { //~^ ERROR hidden lifetime parameters in types are deprecated - //~| HELP indicate the anonymous lifetime + //~| NOTE expected 2 lifetime parameters + //~| HELP consider using the `'_` lifetime println!("{} {}", set.one, set.another); } @@ -55,7 +59,8 @@ macro_rules! autowrapper { fn $fn_name(gift: &str) -> $type_name<'_> { //~^ ERROR hidden lifetime parameters in types are deprecated - //~| HELP indicate the anonymous lifetime + //~| NOTE expected named lifetime parameter + //~| HELP consider using the `'_` lifetime $type_name { gift } } } @@ -69,7 +74,8 @@ macro_rules! anytuple_ref_ty { ($($types:ty),*) => { Ref<'_, ($($types),*)> //~^ ERROR hidden lifetime parameters in types are deprecated - //~| HELP indicate the anonymous lifetime + //~| NOTE expected named lifetime parameter + //~| HELP consider using the `'_` lifetime } } @@ -77,7 +83,8 @@ fn main() { let honesty = RefCell::new((4, 'e')); let loyalty: Ref<'_, (u32, char)> = honesty.borrow(); //~^ ERROR hidden lifetime parameters in types are deprecated - //~| HELP indicate the anonymous lifetime + //~| NOTE expected named lifetime parameter + //~| HELP consider using the `'_` lifetime let generosity = Ref::map(loyalty, |t| &t.0); let laughter = RefCell::new((true, "magic")); diff --git a/src/test/ui/in-band-lifetimes/elided-lifetimes.rs b/src/test/ui/in-band-lifetimes/elided-lifetimes.rs index b729a15a29edd..d55eb854ed2bd 100644 --- a/src/test/ui/in-band-lifetimes/elided-lifetimes.rs +++ b/src/test/ui/in-band-lifetimes/elided-lifetimes.rs @@ -5,23 +5,24 @@ #![deny(elided_lifetimes_in_paths)] //~^ NOTE the lint level is defined here -use std::cell::{RefCell, Ref}; +use std::cell::{Ref, RefCell}; - -struct Foo<'a> { x: &'a u32 } +struct Foo<'a> { + x: &'a u32, +} fn foo(x: &Foo) { //~^ ERROR hidden lifetime parameters in types are deprecated - //~| HELP indicate the anonymous lifetime + //~| NOTE expected named lifetime parameter + //~| HELP consider using the `'_` lifetime } fn bar(x: &Foo<'_>) {} - struct Wrapped<'a>(&'a str); struct WrappedWithBow<'a> { - gift: &'a str + gift: &'a str, } struct MatchedSet<'a, 'b> { @@ -31,19 +32,22 @@ struct MatchedSet<'a, 'b> { fn wrap_gift(gift: &str) -> Wrapped { //~^ ERROR hidden lifetime parameters in types are deprecated - //~| HELP indicate the anonymous lifetime + //~| NOTE expected named lifetime parameter + //~| HELP consider using the `'_` lifetime Wrapped(gift) } fn wrap_gift_with_bow(gift: &str) -> WrappedWithBow { //~^ ERROR hidden lifetime parameters in types are deprecated - //~| HELP indicate the anonymous lifetime + //~| NOTE expected named lifetime parameter + //~| HELP consider using the `'_` lifetime WrappedWithBow { gift } } fn inspect_matched_set(set: MatchedSet) { //~^ ERROR hidden lifetime parameters in types are deprecated - //~| HELP indicate the anonymous lifetime + //~| NOTE expected 2 lifetime parameters + //~| HELP consider using the `'_` lifetime println!("{} {}", set.one, set.another); } @@ -55,7 +59,8 @@ macro_rules! autowrapper { fn $fn_name(gift: &str) -> $type_name { //~^ ERROR hidden lifetime parameters in types are deprecated - //~| HELP indicate the anonymous lifetime + //~| NOTE expected named lifetime parameter + //~| HELP consider using the `'_` lifetime $type_name { gift } } } @@ -69,7 +74,8 @@ macro_rules! anytuple_ref_ty { ($($types:ty),*) => { Ref<($($types),*)> //~^ ERROR hidden lifetime parameters in types are deprecated - //~| HELP indicate the anonymous lifetime + //~| NOTE expected named lifetime parameter + //~| HELP consider using the `'_` lifetime } } @@ -77,7 +83,8 @@ fn main() { let honesty = RefCell::new((4, 'e')); let loyalty: Ref<(u32, char)> = honesty.borrow(); //~^ ERROR hidden lifetime parameters in types are deprecated - //~| HELP indicate the anonymous lifetime + //~| NOTE expected named lifetime parameter + //~| HELP consider using the `'_` lifetime let generosity = Ref::map(loyalty, |t| &t.0); let laughter = RefCell::new((true, "magic")); diff --git a/src/test/ui/in-band-lifetimes/elided-lifetimes.stderr b/src/test/ui/in-band-lifetimes/elided-lifetimes.stderr index 037ce401b3cc9..c7cfaa9a0189e 100644 --- a/src/test/ui/in-band-lifetimes/elided-lifetimes.stderr +++ b/src/test/ui/in-band-lifetimes/elided-lifetimes.stderr @@ -1,60 +1,92 @@ error: hidden lifetime parameters in types are deprecated - --> $DIR/elided-lifetimes.rs:13:12 + --> $DIR/elided-lifetimes.rs:14:12 | LL | fn foo(x: &Foo) { - | ^^^- help: indicate the anonymous lifetime: `<'_>` + | ^^^ expected named lifetime parameter | note: the lint level is defined here --> $DIR/elided-lifetimes.rs:5:9 | LL | #![deny(elided_lifetimes_in_paths)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider using the `'_` lifetime + | +LL | fn foo(x: &Foo<'_>) { + | ~~~~~~~ error: hidden lifetime parameters in types are deprecated - --> $DIR/elided-lifetimes.rs:32:29 + --> $DIR/elided-lifetimes.rs:33:29 | LL | fn wrap_gift(gift: &str) -> Wrapped { - | ^^^^^^^- help: indicate the anonymous lifetime: `<'_>` + | ^^^^^^^ expected named lifetime parameter + | +help: consider using the `'_` lifetime + | +LL | fn wrap_gift(gift: &str) -> Wrapped<'_> { + | ~~~~~~~~~~~ error: hidden lifetime parameters in types are deprecated - --> $DIR/elided-lifetimes.rs:38:38 + --> $DIR/elided-lifetimes.rs:40:38 | LL | fn wrap_gift_with_bow(gift: &str) -> WrappedWithBow { - | ^^^^^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>` + | ^^^^^^^^^^^^^^ expected named lifetime parameter + | +help: consider using the `'_` lifetime + | +LL | fn wrap_gift_with_bow(gift: &str) -> WrappedWithBow<'_> { + | ~~~~~~~~~~~~~~~~~~ error: hidden lifetime parameters in types are deprecated - --> $DIR/elided-lifetimes.rs:44:29 + --> $DIR/elided-lifetimes.rs:47:29 | LL | fn inspect_matched_set(set: MatchedSet) { - | ^^^^^^^^^^- help: indicate the anonymous lifetimes: `<'_, '_>` + | ^^^^^^^^^^ expected 2 lifetime parameters + | +help: consider using the `'_` lifetime + | +LL | fn inspect_matched_set(set: MatchedSet<'_, '_>) { + | ~~~~~~~~~~~~~~~~~~ error: hidden lifetime parameters in types are deprecated - --> $DIR/elided-lifetimes.rs:56:36 + --> $DIR/elided-lifetimes.rs:60:36 | LL | fn $fn_name(gift: &str) -> $type_name { - | ^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>` + | ^^^^^^^^^^ expected named lifetime parameter ... LL | autowrapper!(Autowrapped, autowrap_gift, 'a); | -------------------------------------------- in this macro invocation | = note: this error originates in the macro `autowrapper` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider using the `'_` lifetime + | +LL | fn $fn_name(gift: &str) -> $type_name<'_> { + | ~~~~~~~~~~~~~~ error: hidden lifetime parameters in types are deprecated - --> $DIR/elided-lifetimes.rs:78:18 + --> $DIR/elided-lifetimes.rs:84:22 | LL | let loyalty: Ref<(u32, char)> = honesty.borrow(); - | ^^^^^^^^^^^^^^^^ help: indicate the anonymous lifetime: `Ref<'_, (u32, char)>` + | ^ expected named lifetime parameter + | +help: consider using the `'_` lifetime + | +LL | let loyalty: Ref<'_, (u32, char)> = honesty.borrow(); + | +++ error: hidden lifetime parameters in types are deprecated - --> $DIR/elided-lifetimes.rs:70:9 + --> $DIR/elided-lifetimes.rs:75:13 | LL | Ref<($($types),*)> - | ^^^^^^^^^^^^^^^^^^ help: indicate the anonymous lifetime: `Ref<'_, ($($types),*)>` + | ^ expected named lifetime parameter ... LL | let yellow: anytuple_ref_ty!(bool, &str) = laughter.borrow(); | ---------------------------- in this macro invocation | = note: this error originates in the macro `anytuple_ref_ty` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider using the `'_` lifetime + | +LL | Ref<'_, ($($types),*)> + | +++ error: aborting due to 7 previous errors diff --git a/src/test/ui/lint/force-warn/allowed-by-default-lint.stderr b/src/test/ui/lint/force-warn/allowed-by-default-lint.stderr index baa47cbb10fd5..f5e8b41b1634e 100644 --- a/src/test/ui/lint/force-warn/allowed-by-default-lint.stderr +++ b/src/test/ui/lint/force-warn/allowed-by-default-lint.stderr @@ -2,9 +2,13 @@ warning: hidden lifetime parameters in types are deprecated --> $DIR/allowed-by-default-lint.rs:9:12 | LL | fn foo(x: &Foo) {} - | ^^^- help: indicate the anonymous lifetime: `<'_>` + | ^^^ expected named lifetime parameter | = note: requested on the command line with `--force-warn elided-lifetimes-in-paths` +help: consider using the `'_` lifetime + | +LL | fn foo(x: &Foo<'_>) {} + | ~~~~~~~ warning: 1 warning emitted diff --git a/src/test/ui/lint/reasons.rs b/src/test/ui/lint/reasons.rs index 34cac4968a84f..b1792e2e9cbf8 100644 --- a/src/test/ui/lint/reasons.rs +++ b/src/test/ui/lint/reasons.rs @@ -1,7 +1,6 @@ // check-pass #![feature(lint_reasons)] - #![warn(elided_lifetimes_in_paths, //~^ NOTE the lint level is defined here reason = "explicit anonymous lifetimes aid reasoning about ownership")] @@ -20,8 +19,9 @@ pub struct CheaterDetectionMechanism {} impl fmt::Debug for CheaterDetectionMechanism { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { //~^ WARN hidden lifetime parameters in types are deprecated + //~| NOTE expected named lifetime parameter //~| NOTE explicit anonymous lifetimes aid - //~| HELP indicate the anonymous lifetime + //~| HELP consider using the `'_` lifetime fmt.debug_struct("CheaterDetectionMechanism").finish() } } diff --git a/src/test/ui/lint/reasons.stderr b/src/test/ui/lint/reasons.stderr index 150237c6be293..f797c89a03269 100644 --- a/src/test/ui/lint/reasons.stderr +++ b/src/test/ui/lint/reasons.stderr @@ -1,15 +1,19 @@ warning: hidden lifetime parameters in types are deprecated - --> $DIR/reasons.rs:21:29 + --> $DIR/reasons.rs:20:29 | LL | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - | ^^^^^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>` + | ^^^^^^^^^^^^^^ expected named lifetime parameter | = note: explicit anonymous lifetimes aid reasoning about ownership note: the lint level is defined here - --> $DIR/reasons.rs:5:9 + --> $DIR/reasons.rs:4:9 | LL | #![warn(elided_lifetimes_in_paths, | ^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider using the `'_` lifetime + | +LL | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + | ~~~~~~~~~~~~~~~~~~ warning: variable `Social_exchange_psychology` should have a snake case name --> $DIR/reasons.rs:30:9 @@ -20,7 +24,7 @@ LL | let Social_exchange_psychology = CheaterDetectionMechanism {}; = note: people shouldn't have to change their usual style habits to contribute to our project note: the lint level is defined here - --> $DIR/reasons.rs:9:5 + --> $DIR/reasons.rs:8:5 | LL | nonstandard_style, | ^^^^^^^^^^^^^^^^^ From 9d6f4747313a5944875b724448371643b94dfb04 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 31 Oct 2021 17:54:47 +0100 Subject: [PATCH 4/7] Simplify lowering. --- compiler/rustc_ast_lowering/src/path.rs | 68 +++++++++++-------------- 1 file changed, 31 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index ab87867bb0388..cf0ee4fc28fe2 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -268,7 +268,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let has_lifetimes = generic_args.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_))); - if !generic_args.parenthesized && !has_lifetimes { + if !generic_args.parenthesized && !has_lifetimes && expected_lifetimes > 0 { // 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() { @@ -286,49 +286,43 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .map(GenericArg::Lifetime) .chain(generic_args.args.into_iter()) .collect(); - if expected_lifetimes > 0 && param_mode == ParamMode::Explicit { + // In create-parameter mode we error here because we don't want to support + // deprecated impl elision in new features like impl elision and `async fn`, + // both of which work using the `CreateParameter` mode: + // + // impl Foo for std::cell::Ref // note lack of '_ + // async fn foo(_: std::cell::Ref) { ... } + if let (ParamMode::Explicit, AnonymousLifetimeMode::CreateParameter) = + (param_mode, self.anonymous_lifetime_mode) + { let anon_lt_suggestion = vec!["'_"; expected_lifetimes].join(", "); let no_non_lt_args = generic_args.args.len() == expected_lifetimes; let no_bindings = generic_args.bindings.is_empty(); - let (incl_angl_brckt, insertion_sp, suggestion) = if no_non_lt_args && no_bindings { + let (incl_angl_brckt, suggestion) = if no_non_lt_args && no_bindings { // If there are no generic args, our suggestion can include the angle brackets. - (true, path_span.shrink_to_hi(), format!("<{}>", anon_lt_suggestion)) + (true, format!("<{}>", anon_lt_suggestion)) } else { // Otherwise we'll insert a `'_, ` right after the opening bracket. - let span = generic_args - .span - .with_lo(generic_args.span.lo() + BytePos(1)) - .shrink_to_lo(); - (false, span, format!("{}, ", anon_lt_suggestion)) + (false, format!("{}, ", anon_lt_suggestion)) }; - match self.anonymous_lifetime_mode { - // In create-parameter mode we error here because we don't want to support - // deprecated impl elision in new features like impl elision and `async fn`, - // both of which work using the `CreateParameter` mode: - // - // impl Foo for std::cell::Ref // note lack of '_ - // async fn foo(_: std::cell::Ref) { ... } - AnonymousLifetimeMode::CreateParameter => { - let mut err = struct_span_err!( - self.sess, - path_span, - E0726, - "implicit elided lifetime not allowed here" - ); - rustc_errors::add_elided_lifetime_in_path_suggestion( - &self.sess.source_map(), - &mut err, - expected_lifetimes, - path_span, - incl_angl_brckt, - insertion_sp, - suggestion, - ); - err.note("assuming a `'static` lifetime..."); - err.emit(); - } - AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => {} - } + let insertion_sp = elided_lifetime_span.shrink_to_hi(); + let mut err = struct_span_err!( + self.sess, + path_span, + E0726, + "implicit elided lifetime not allowed here" + ); + rustc_errors::add_elided_lifetime_in_path_suggestion( + &self.sess.source_map(), + &mut err, + expected_lifetimes, + path_span, + incl_angl_brckt, + insertion_sp, + suggestion, + ); + err.note("assuming a `'static` lifetime..."); + err.emit(); } } From 8609dc497321030eb23f8cea25aa1c7992d162a8 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 31 Oct 2021 18:24:55 +0100 Subject: [PATCH 5/7] Complete test. --- .../in-band-lifetimes/elided-lifetimes.fixed | 17 +++++++++ .../ui/in-band-lifetimes/elided-lifetimes.rs | 17 +++++++++ .../in-band-lifetimes/elided-lifetimes.stderr | 36 ++++++++++++++++--- 3 files changed, 66 insertions(+), 4 deletions(-) diff --git a/src/test/ui/in-band-lifetimes/elided-lifetimes.fixed b/src/test/ui/in-band-lifetimes/elided-lifetimes.fixed index ca70242ef3d67..35e0701103c51 100644 --- a/src/test/ui/in-band-lifetimes/elided-lifetimes.fixed +++ b/src/test/ui/in-band-lifetimes/elided-lifetimes.fixed @@ -51,6 +51,15 @@ fn inspect_matched_set(set: MatchedSet<'_, '_>) { println!("{} {}", set.one, set.another); } +// Verify that the lint does not fire, because the added `'_` wouldn't be resolved correctly. +fn match_sets() -> MatchedSet<'static, 'static> { + //~^ ERROR missing lifetime specifiers + //~| NOTE expected 2 lifetime parameters + //~| HELP this function's return type contains a borrowed value + //~| HELP consider using the `'static` lifetime + MatchedSet { one: "one", another: "another" } +} + macro_rules! autowrapper { ($type_name:ident, $fn_name:ident, $lt:lifetime) => { struct $type_name<$lt> { @@ -61,6 +70,9 @@ macro_rules! autowrapper { //~^ ERROR hidden lifetime parameters in types are deprecated //~| NOTE expected named lifetime parameter //~| HELP consider using the `'_` lifetime + //~| ERROR hidden lifetime parameters in types are deprecated + //~| NOTE expected named lifetime parameter + //~| HELP consider using the `'_` lifetime $type_name { gift } } } @@ -70,6 +82,11 @@ autowrapper!(Autowrapped, autowrap_gift, 'a); //~^ NOTE in this expansion of autowrapper! //~| NOTE in this expansion of autowrapper! +// Verify that rustfix does not try to apply the fix twice. +autowrapper!(AutowrappedAgain, autowrap_gift_again, 'a); +//~^ NOTE in this expansion of autowrapper! +//~| NOTE in this expansion of autowrapper! + macro_rules! anytuple_ref_ty { ($($types:ty),*) => { Ref<'_, ($($types),*)> diff --git a/src/test/ui/in-band-lifetimes/elided-lifetimes.rs b/src/test/ui/in-band-lifetimes/elided-lifetimes.rs index d55eb854ed2bd..4ad6141eda58c 100644 --- a/src/test/ui/in-band-lifetimes/elided-lifetimes.rs +++ b/src/test/ui/in-band-lifetimes/elided-lifetimes.rs @@ -51,6 +51,15 @@ fn inspect_matched_set(set: MatchedSet) { println!("{} {}", set.one, set.another); } +// Verify that the lint does not fire, because the added `'_` wouldn't be resolved correctly. +fn match_sets() -> MatchedSet { + //~^ ERROR missing lifetime specifiers + //~| NOTE expected 2 lifetime parameters + //~| HELP this function's return type contains a borrowed value + //~| HELP consider using the `'static` lifetime + MatchedSet { one: "one", another: "another" } +} + macro_rules! autowrapper { ($type_name:ident, $fn_name:ident, $lt:lifetime) => { struct $type_name<$lt> { @@ -61,6 +70,9 @@ macro_rules! autowrapper { //~^ ERROR hidden lifetime parameters in types are deprecated //~| NOTE expected named lifetime parameter //~| HELP consider using the `'_` lifetime + //~| ERROR hidden lifetime parameters in types are deprecated + //~| NOTE expected named lifetime parameter + //~| HELP consider using the `'_` lifetime $type_name { gift } } } @@ -70,6 +82,11 @@ autowrapper!(Autowrapped, autowrap_gift, 'a); //~^ NOTE in this expansion of autowrapper! //~| NOTE in this expansion of autowrapper! +// Verify that rustfix does not try to apply the fix twice. +autowrapper!(AutowrappedAgain, autowrap_gift_again, 'a); +//~^ NOTE in this expansion of autowrapper! +//~| NOTE in this expansion of autowrapper! + macro_rules! anytuple_ref_ty { ($($types:ty),*) => { Ref<($($types),*)> diff --git a/src/test/ui/in-band-lifetimes/elided-lifetimes.stderr b/src/test/ui/in-band-lifetimes/elided-lifetimes.stderr index c7cfaa9a0189e..b6994a3673ab3 100644 --- a/src/test/ui/in-band-lifetimes/elided-lifetimes.stderr +++ b/src/test/ui/in-band-lifetimes/elided-lifetimes.stderr @@ -47,8 +47,20 @@ help: consider using the `'_` lifetime LL | fn inspect_matched_set(set: MatchedSet<'_, '_>) { | ~~~~~~~~~~~~~~~~~~ +error[E0106]: missing lifetime specifiers + --> $DIR/elided-lifetimes.rs:55:20 + | +LL | fn match_sets() -> MatchedSet { + | ^^^^^^^^^^ expected 2 lifetime parameters + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | fn match_sets() -> MatchedSet<'static, 'static> { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + error: hidden lifetime parameters in types are deprecated - --> $DIR/elided-lifetimes.rs:60:36 + --> $DIR/elided-lifetimes.rs:69:36 | LL | fn $fn_name(gift: &str) -> $type_name { | ^^^^^^^^^^ expected named lifetime parameter @@ -63,7 +75,22 @@ LL | fn $fn_name(gift: &str) -> $type_name<'_> { | ~~~~~~~~~~~~~~ error: hidden lifetime parameters in types are deprecated - --> $DIR/elided-lifetimes.rs:84:22 + --> $DIR/elided-lifetimes.rs:69:36 + | +LL | fn $fn_name(gift: &str) -> $type_name { + | ^^^^^^^^^^ expected named lifetime parameter +... +LL | autowrapper!(AutowrappedAgain, autowrap_gift_again, 'a); + | ------------------------------------------------------- in this macro invocation + | + = note: this error originates in the macro `autowrapper` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider using the `'_` lifetime + | +LL | fn $fn_name(gift: &str) -> $type_name<'_> { + | ~~~~~~~~~~~~~~ + +error: hidden lifetime parameters in types are deprecated + --> $DIR/elided-lifetimes.rs:101:22 | LL | let loyalty: Ref<(u32, char)> = honesty.borrow(); | ^ expected named lifetime parameter @@ -74,7 +101,7 @@ LL | let loyalty: Ref<'_, (u32, char)> = honesty.borrow(); | +++ error: hidden lifetime parameters in types are deprecated - --> $DIR/elided-lifetimes.rs:75:13 + --> $DIR/elided-lifetimes.rs:92:13 | LL | Ref<($($types),*)> | ^ expected named lifetime parameter @@ -88,5 +115,6 @@ help: consider using the `'_` lifetime LL | Ref<'_, ($($types),*)> | +++ -error: aborting due to 7 previous errors +error: aborting due to 9 previous errors +For more information about this error, try `rustc --explain E0106`. From dd28f9634236de3bf170b5a61e231a9e720ad7c6 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 31 Oct 2021 18:39:39 +0100 Subject: [PATCH 6/7] Handle `allow(elided_lifetimes_in_paths)`. --- .../rustc_resolve/src/late/diagnostics.rs | 59 +++++++++---------- .../in-band-lifetimes/elided-lifetimes.fixed | 8 +++ .../ui/in-band-lifetimes/elided-lifetimes.rs | 8 +++ .../in-band-lifetimes/elided-lifetimes.stderr | 2 +- 4 files changed, 45 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 2b032847c6a7f..df72521a83e11 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1950,38 +1950,35 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { } crate fn report_elided_lifetime_in_ty(&self, lifetime_refs: &[&hir::Lifetime]) { - let missing_lifetimes = lifetime_refs - .iter() - .filter(|a| matches!(a, hir::Lifetime { name: hir::LifetimeName::ImplicitMissing, .. })) - .count(); - - if missing_lifetimes > 0 { - let mut spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect(); - spans.sort(); - let mut spans_dedup = spans.clone(); - spans_dedup.dedup(); - let spans_with_counts: Vec<_> = spans_dedup - .into_iter() - .map(|sp| (sp, spans.iter().filter(|nsp| *nsp == &sp).count())) - .collect(); + let Some(missing_lifetime) = lifetime_refs.iter().find(|lt| { + lt.name == hir::LifetimeName::ImplicitMissing + }) else { return }; + + let mut spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect(); + spans.sort(); + let mut spans_dedup = spans.clone(); + spans_dedup.dedup(); + let spans_with_counts: Vec<_> = spans_dedup + .into_iter() + .map(|sp| (sp, spans.iter().filter(|nsp| *nsp == &sp).count())) + .collect(); - self.tcx.struct_span_lint_hir( - rustc_session::lint::builtin::ELIDED_LIFETIMES_IN_PATHS, - hir::CRATE_HIR_ID, - spans, - |lint| { - let mut db = lint.build("hidden lifetime parameters in types are deprecated"); - self.add_missing_lifetime_specifiers_label( - &mut db, - spans_with_counts, - &FxHashSet::from_iter([kw::UnderscoreLifetime]), - Vec::new(), - &[], - ); - db.emit() - }, - ); - } + self.tcx.struct_span_lint_hir( + rustc_session::lint::builtin::ELIDED_LIFETIMES_IN_PATHS, + missing_lifetime.hir_id, + spans, + |lint| { + let mut db = lint.build("hidden lifetime parameters in types are deprecated"); + self.add_missing_lifetime_specifiers_label( + &mut db, + spans_with_counts, + &FxHashSet::from_iter([kw::UnderscoreLifetime]), + Vec::new(), + &[], + ); + db.emit() + }, + ); } // FIXME(const_generics): This patches over an ICE caused by non-'static lifetimes in const diff --git a/src/test/ui/in-band-lifetimes/elided-lifetimes.fixed b/src/test/ui/in-band-lifetimes/elided-lifetimes.fixed index 35e0701103c51..87a79b8813777 100644 --- a/src/test/ui/in-band-lifetimes/elided-lifetimes.fixed +++ b/src/test/ui/in-band-lifetimes/elided-lifetimes.fixed @@ -96,6 +96,14 @@ macro_rules! anytuple_ref_ty { } } +#[allow(elided_lifetimes_in_paths)] +mod blah { + struct Thing<'a>(&'a i32); + struct Bar(T); + + fn foo(b: Bar) {} +} + fn main() { let honesty = RefCell::new((4, 'e')); let loyalty: Ref<'_, (u32, char)> = honesty.borrow(); diff --git a/src/test/ui/in-band-lifetimes/elided-lifetimes.rs b/src/test/ui/in-band-lifetimes/elided-lifetimes.rs index 4ad6141eda58c..28323a22427b6 100644 --- a/src/test/ui/in-band-lifetimes/elided-lifetimes.rs +++ b/src/test/ui/in-band-lifetimes/elided-lifetimes.rs @@ -96,6 +96,14 @@ macro_rules! anytuple_ref_ty { } } +#[allow(elided_lifetimes_in_paths)] +mod blah { + struct Thing<'a>(&'a i32); + struct Bar(T); + + fn foo(b: Bar) {} +} + fn main() { let honesty = RefCell::new((4, 'e')); let loyalty: Ref<(u32, char)> = honesty.borrow(); diff --git a/src/test/ui/in-band-lifetimes/elided-lifetimes.stderr b/src/test/ui/in-band-lifetimes/elided-lifetimes.stderr index b6994a3673ab3..2e65461b321e9 100644 --- a/src/test/ui/in-band-lifetimes/elided-lifetimes.stderr +++ b/src/test/ui/in-band-lifetimes/elided-lifetimes.stderr @@ -90,7 +90,7 @@ LL | fn $fn_name(gift: &str) -> $type_name<'_> { | ~~~~~~~~~~~~~~ error: hidden lifetime parameters in types are deprecated - --> $DIR/elided-lifetimes.rs:101:22 + --> $DIR/elided-lifetimes.rs:109:22 | LL | let loyalty: Ref<(u32, char)> = honesty.borrow(); | ^ expected named lifetime parameter From e6f50681c3021d0bd12ecc35089467b8e3bc6182 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Fri, 26 Nov 2021 23:07:21 +0100 Subject: [PATCH 7/7] Merge Implicit and ImplicitMissing. --- compiler/rustc_ast_lowering/src/lib.rs | 22 ++++++------------- .../src/diagnostics/region_name.rs | 4 +--- compiler/rustc_hir/src/hir.rs | 15 +++++-------- compiler/rustc_hir/src/intravisit.rs | 3 +-- .../rustc_resolve/src/late/diagnostics.rs | 5 ++--- compiler/rustc_resolve/src/late/lifetimes.rs | 5 ++--- 6 files changed, 19 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index a561475c76a0b..2a246a99a7032 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1786,7 +1786,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { GenericArg::Lifetime(hir::Lifetime { hir_id: self.next_id(), span: self.lower_span(span), - name: hir::LifetimeName::Implicit, + name: hir::LifetimeName::Implicit(false), }))); let generic_args = self.arena.alloc_from_iter(generic_args); @@ -1927,8 +1927,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }); let param_name = match lt.name { hir::LifetimeName::Param(param_name) => param_name, - hir::LifetimeName::Implicit - | hir::LifetimeName::ImplicitMissing + hir::LifetimeName::Implicit(_) | hir::LifetimeName::Underscore | hir::LifetimeName::Static => hir::ParamName::Plain(lt.name.ident()), hir::LifetimeName::ImplicitObjectLifetimeDefault => { @@ -2291,7 +2290,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { AnonymousLifetimeMode::ReportError => self.new_error_lifetime(None, span), - AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span), + AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span, false), } } @@ -2344,12 +2343,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // lifetime. Instead, we simply create an implicit lifetime, which will be checked // later, at which point a suitable error will be emitted. AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => { - if param_mode == ParamMode::Explicit { - let id = self.resolver.next_node_id(); - self.new_named_lifetime(id, span, hir::LifetimeName::ImplicitMissing) - } else { - self.new_implicit_lifetime(span) - } + self.new_implicit_lifetime(span, param_mode == ParamMode::Explicit) } } } @@ -2392,11 +2386,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { r } - fn new_implicit_lifetime(&mut self, span: Span) -> hir::Lifetime { + fn new_implicit_lifetime(&mut self, span: Span, missing: bool) -> hir::Lifetime { hir::Lifetime { hir_id: self.next_id(), span: self.lower_span(span), - name: hir::LifetimeName::Implicit, + name: hir::LifetimeName::Implicit(missing), } } @@ -2543,9 +2537,7 @@ fn lifetimes_from_impl_trait_bounds( fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) { let name = match lifetime.name { - hir::LifetimeName::Implicit - | hir::LifetimeName::ImplicitMissing - | hir::LifetimeName::Underscore => { + hir::LifetimeName::Implicit(_) | hir::LifetimeName::Underscore => { if self.collect_elided_lifetimes { // Use `'_` for both implicit and underscore lifetimes in // `type Foo<'_> = impl SomeTrait<'_>;`. diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 64df452c73978..64a7a25dc86ac 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -584,9 +584,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span)) } - hir::LifetimeName::ImplicitObjectLifetimeDefault - | hir::LifetimeName::Implicit - | hir::LifetimeName::ImplicitMissing => { + hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit(_) => { // In this case, the user left off the lifetime; so // they wrote something like: // diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 707861f562d91..df031c16f9903 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -92,10 +92,9 @@ pub enum LifetimeName { Param(ParamName), /// User wrote nothing (e.g., the lifetime in `&u32`). - Implicit, - - /// User wrote nothing and should have. - ImplicitMissing, + /// + /// missing: the user should have written something. + Implicit(bool), /// Implicit lifetime in a context like `dyn Foo`. This is /// distinguished from implicit lifetimes elsewhere because the @@ -125,8 +124,7 @@ impl LifetimeName { pub fn ident(&self) -> Ident { match *self { LifetimeName::ImplicitObjectLifetimeDefault - | LifetimeName::Implicit - | LifetimeName::ImplicitMissing + | LifetimeName::Implicit(_) | LifetimeName::Error => Ident::empty(), LifetimeName::Underscore => Ident::with_dummy_span(kw::UnderscoreLifetime), LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime), @@ -137,8 +135,7 @@ impl LifetimeName { pub fn is_elided(&self) -> bool { match self { LifetimeName::ImplicitObjectLifetimeDefault - | LifetimeName::Implicit - | LifetimeName::ImplicitMissing + | LifetimeName::Implicit(_) | LifetimeName::Underscore => true, // It might seem surprising that `Fresh(_)` counts as @@ -3303,7 +3300,7 @@ mod size_asserts { rustc_data_structures::static_assert_size!(super::Expr<'static>, 64); rustc_data_structures::static_assert_size!(super::Pat<'static>, 88); rustc_data_structures::static_assert_size!(super::QPath<'static>, 24); - rustc_data_structures::static_assert_size!(super::Ty<'static>, 72); + rustc_data_structures::static_assert_size!(super::Ty<'static>, 80); rustc_data_structures::static_assert_size!(super::Item<'static>, 184); rustc_data_structures::static_assert_size!(super::TraitItem<'static>, 128); diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 5f8e4ba2d1398..21f89104c4b58 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -545,8 +545,7 @@ pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime | LifetimeName::Param(ParamName::Error) | LifetimeName::Static | LifetimeName::Error - | LifetimeName::Implicit - | LifetimeName::ImplicitMissing + | LifetimeName::Implicit(_) | LifetimeName::ImplicitObjectLifetimeDefault | LifetimeName::Underscore => {} } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index df72521a83e11..c293a7bb6bdde 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1951,7 +1951,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { crate fn report_elided_lifetime_in_ty(&self, lifetime_refs: &[&hir::Lifetime]) { let Some(missing_lifetime) = lifetime_refs.iter().find(|lt| { - lt.name == hir::LifetimeName::ImplicitMissing + lt.name == hir::LifetimeName::Implicit(true) }) else { return }; let mut spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect(); @@ -2407,8 +2407,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { ); let is_allowed_lifetime = matches!( lifetime_ref.name, - hir::LifetimeName::Implicit - | hir::LifetimeName::ImplicitMissing + hir::LifetimeName::Implicit(_) | hir::LifetimeName::Static | hir::LifetimeName::Underscore ); diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 0de6b8695ca3b..b32c20053ee6a 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -923,7 +923,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } }); match lifetime.name { - LifetimeName::Implicit | hir::LifetimeName::ImplicitMissing => { + LifetimeName::Implicit(_) => { // For types like `dyn Foo`, we should // generate a special form of elided. span_bug!(ty.span, "object-lifetime-default expected, not implicit",); @@ -3283,8 +3283,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { .emit(); } hir::LifetimeName::Param(_) - | hir::LifetimeName::Implicit - | hir::LifetimeName::ImplicitMissing => { + | hir::LifetimeName::Implicit(_) => { self.resolve_lifetime_ref(lt); } hir::LifetimeName::ImplicitObjectLifetimeDefault => {