diff options
| author | Camille GILLOT <gillot.camille@gmail.com> | 2021-07-11 15:04:57 +0200 |
|---|---|---|
| committer | Camille GILLOT <gillot.camille@gmail.com> | 2021-11-30 22:55:07 +0100 |
| commit | 5ea7ea8a5786729d3e8d0d513819f52b4d9047dd (patch) | |
| tree | f7c72c730650d096e7fdce85d7322eba1dd7a6ab /compiler | |
| parent | ac03470c3ba4959d74ca1b61a57e0bcfb6d2d2f3 (diff) | |
| download | rust-5ea7ea8a5786729d3e8d0d513819f52b4d9047dd.tar.gz rust-5ea7ea8a5786729d3e8d0d513819f52b4d9047dd.zip | |
Lint elided lifetimes in path during lifetime resolution.
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_ast_lowering/src/lib.rs | 17 | ||||
| -rw-r--r-- | compiler/rustc_ast_lowering/src/path.rs | 22 | ||||
| -rw-r--r-- | compiler/rustc_borrowck/src/diagnostics/region_name.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_hir/src/hir.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_hir/src/intravisit.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/late/diagnostics.rs | 40 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/late/lifetimes.rs | 26 |
7 files changed, 82 insertions, 33 deletions
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 2b3a538772e..a561475c76a 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<Item = hir::Lifetime> + 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 929f427484d..ab87867bb03 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 5edb52b0b65..64df452c739 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 c67d3df3ded..e56761ea39a 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, but should have provided something. + 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 cff543760f4..5f8e4ba2d13 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 8c917fc466d..2186a9a73c5 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1950,6 +1950,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. @@ -2376,7 +2411,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 85e704874e2..0427317aa90 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 => { |
