From aa2b5ef6356f41f9173fe3dc1e5dc3e27290436c Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 18 Nov 2021 19:59:26 +0100 Subject: [PATCH 1/8] Count number of lifetime parameters in a separate pass. --- compiler/rustc_resolve/src/late.rs | 52 ++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 763f31622bc1f..2f6ac4020bc65 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1006,7 +1006,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { match item.kind { ItemKind::TyAlias(box TyAlias { ref generics, .. }) | ItemKind::Fn(box Fn { ref generics, .. }) => { - self.compute_num_lifetime_params(item.id, generics); self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { visit::walk_item(this, item) }); @@ -1015,7 +1014,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ItemKind::Enum(_, ref generics) | ItemKind::Struct(_, ref generics) | ItemKind::Union(_, ref generics) => { - self.compute_num_lifetime_params(item.id, generics); self.resolve_adt(item, generics); } @@ -1026,12 +1024,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { items: ref impl_items, .. }) => { - self.compute_num_lifetime_params(item.id, generics); self.resolve_implementation(generics, of_trait, &self_ty, item.id, impl_items); } ItemKind::Trait(box Trait { ref generics, ref bounds, ref items, .. }) => { - self.compute_num_lifetime_params(item.id, generics); // Create a new rib for the trait-wide type parameters. self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { let def = this.r.local_def_id(item.id).to_def_id(); @@ -1083,7 +1079,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } ItemKind::TraitAlias(ref generics, ref bounds) => { - self.compute_num_lifetime_params(item.id, generics); // Create a new rib for the trait-wide type parameters. self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { let def = this.r.local_def_id(item.id).to_def_id(); @@ -2576,20 +2571,51 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { Some((ident.name, ns)), ) } +} - fn compute_num_lifetime_params(&mut self, id: NodeId, generics: &Generics) { - let def_id = self.r.local_def_id(id); - let count = generics - .params - .iter() - .filter(|param| matches!(param.kind, ast::GenericParamKind::Lifetime { .. })) - .count(); - self.r.item_generics_num_lifetimes.insert(def_id, count); +struct LifetimeCountVisitor<'a, 'b> { + r: &'b mut Resolver<'a>, +} + +/// Walks the whole crate in DFS order, visiting each item, counting the declared number of +/// lifetime generic parameters. +impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_> { + fn visit_item(&mut self, item: &'ast Item) { + match &item.kind { + ItemKind::TyAlias(box TyAlias { ref generics, .. }) + | ItemKind::Fn(box Fn { ref generics, .. }) + | ItemKind::Enum(_, ref generics) + | ItemKind::Struct(_, ref generics) + | ItemKind::Union(_, ref generics) + | ItemKind::Impl(box Impl { ref generics, .. }) + | ItemKind::Trait(box Trait { ref generics, .. }) + | ItemKind::TraitAlias(ref generics, _) => { + let def_id = self.r.local_def_id(item.id); + let count = generics + .params + .iter() + .filter(|param| matches!(param.kind, ast::GenericParamKind::Lifetime { .. })) + .count(); + self.r.item_generics_num_lifetimes.insert(def_id, count); + } + + ItemKind::Mod(..) + | ItemKind::ForeignMod(..) + | ItemKind::Static(..) + | ItemKind::Const(..) + | ItemKind::Use(..) + | ItemKind::ExternCrate(..) + | ItemKind::MacroDef(..) + | ItemKind::GlobalAsm(..) + | ItemKind::MacCall(..) => {} + } + visit::walk_item(self, item) } } impl<'a> Resolver<'a> { pub(crate) fn late_resolve_crate(&mut self, krate: &Crate) { + visit::walk_crate(&mut LifetimeCountVisitor { r: self }, krate); let mut late_resolution_visitor = LateResolutionVisitor::new(self); visit::walk_crate(&mut late_resolution_visitor, krate); for (id, span) in late_resolution_visitor.diagnostic_metadata.unused_labels.iter() { From e47f66dc0d2697aab816fe045fb00195bac18596 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Fri, 19 Nov 2021 22:03:43 +0100 Subject: [PATCH 2/8] Visit generics inside visit_fn. --- compiler/rustc_ast/src/visit.rs | 19 +++++---- .../rustc_ast_passes/src/ast_validation.rs | 40 +++++++++++-------- compiler/rustc_lint/src/builtin.rs | 1 + compiler/rustc_lint/src/early.rs | 2 +- compiler/rustc_resolve/src/def_collector.rs | 4 +- compiler/rustc_resolve/src/late.rs | 8 +++- src/tools/rustfmt/src/items.rs | 13 ++++-- src/tools/rustfmt/src/visitor.rs | 18 +++++---- 8 files changed, 65 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 3183612597d13..d925c6dd3549a 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -35,7 +35,7 @@ pub enum FnCtxt { #[derive(Copy, Clone, Debug)] pub enum FnKind<'a> { /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`. - Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, Option<&'a Block>), + Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, &'a Generics, Option<&'a Block>), /// E.g., `|x, y| body`. Closure(&'a FnDecl, &'a Expr), @@ -44,7 +44,7 @@ pub enum FnKind<'a> { impl<'a> FnKind<'a> { pub fn header(&self) -> Option<&'a FnHeader> { match *self { - FnKind::Fn(_, _, sig, _, _) => Some(&sig.header), + FnKind::Fn(_, _, sig, _, _, _) => Some(&sig.header), FnKind::Closure(_, _) => None, } } @@ -58,7 +58,7 @@ impl<'a> FnKind<'a> { pub fn decl(&self) -> &'a FnDecl { match self { - FnKind::Fn(_, _, sig, _, _) => &sig.decl, + FnKind::Fn(_, _, sig, _, _, _) => &sig.decl, FnKind::Closure(decl, _) => decl, } } @@ -295,8 +295,8 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { walk_list!(visitor, visit_expr, expr); } ItemKind::Fn(box Fn { defaultness: _, ref generics, ref sig, ref body }) => { - visitor.visit_generics(generics); - let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref()); + let kind = + FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref()); visitor.visit_fn(kind, item.span, item.id) } ItemKind::Mod(_unsafety, ref mod_kind) => match mod_kind { @@ -561,8 +561,7 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignI walk_list!(visitor, visit_expr, expr); } ForeignItemKind::Fn(box Fn { defaultness: _, ref generics, ref sig, ref body }) => { - visitor.visit_generics(generics); - let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, body.as_deref()); + let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, generics, body.as_deref()); visitor.visit_fn(kind, span, id); } ForeignItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => { @@ -644,7 +643,8 @@ pub fn walk_fn_decl<'a, V: Visitor<'a>>(visitor: &mut V, function_declaration: & pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>, _span: Span) { match kind { - FnKind::Fn(_, _, sig, _, body) => { + FnKind::Fn(_, _, sig, _, generics, body) => { + visitor.visit_generics(generics); visitor.visit_fn_header(&sig.header); walk_fn_decl(visitor, &sig.decl); walk_list!(visitor, visit_block, body); @@ -667,8 +667,7 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem, walk_list!(visitor, visit_expr, expr); } AssocItemKind::Fn(box Fn { defaultness: _, ref generics, ref sig, ref body }) => { - visitor.visit_generics(generics); - let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, body.as_deref()); + let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, body.as_deref()); visitor.visit_fn(kind, span, id); } AssocItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => { diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 33727084ccf06..8d815e9552882 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -91,16 +91,18 @@ impl<'a> AstValidator<'a> { self.is_impl_trait_banned = old; } - fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) { - let old = mem::replace(&mut self.is_tilde_const_allowed, true); + fn with_tilde_const(&mut self, allowed: bool, f: impl FnOnce(&mut Self)) { + let old = mem::replace(&mut self.is_tilde_const_allowed, allowed); f(self); self.is_tilde_const_allowed = old; } + fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) { + self.with_tilde_const(true, f) + } + fn with_banned_tilde_const(&mut self, f: impl FnOnce(&mut Self)) { - let old = mem::replace(&mut self.is_tilde_const_allowed, false); - f(self); - self.is_tilde_const_allowed = old; + self.with_tilde_const(false, f) } fn with_let_management( @@ -1202,12 +1204,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } self.visit_vis(&item.vis); self.visit_ident(item.ident); - if let Const::Yes(_) = sig.header.constness { - self.with_tilde_const_allowed(|this| this.visit_generics(generics)); - } else { - self.visit_generics(generics); - } - let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref()); + let kind = + FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref()); self.visit_fn(kind, item.span, item.id); walk_list!(self, visit_attribute, &item.attrs); return; // Avoid visiting again. @@ -1555,13 +1553,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> { FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit, .. }, .. }, _, _, + _, ) = fk { self.maybe_lint_missing_abi(*sig_span, id); } // Functions without bodies cannot have patterns. - if let FnKind::Fn(ctxt, _, sig, _, None) = fk { + if let FnKind::Fn(ctxt, _, sig, _, _, None) = fk { Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| { let (code, msg, label) = match ctxt { FnCtxt::Foreign => ( @@ -1596,7 +1595,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }); } - visit::walk_fn(self, fk, span); + let tilde_const_allowed = + matches!(fk.header(), Some(FnHeader { constness: Const::Yes(_), .. })) + || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_))); + + self.with_tilde_const(tilde_const_allowed, |this| visit::walk_fn(this, fk, span)); } fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { @@ -1670,9 +1673,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> { { self.visit_vis(&item.vis); self.visit_ident(item.ident); - self.with_tilde_const_allowed(|this| this.visit_generics(generics)); - let kind = - FnKind::Fn(FnCtxt::Assoc(ctxt), item.ident, sig, &item.vis, body.as_deref()); + let kind = FnKind::Fn( + FnCtxt::Assoc(ctxt), + item.ident, + sig, + &item.vis, + generics, + body.as_deref(), + ); self.visit_fn(kind, item.span, item.id); } _ => self diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index e6f9246d73242..77fe76af2de21 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -441,6 +441,7 @@ impl EarlyLintPass for UnsafeCode { _, ast::FnSig { header: ast::FnHeader { unsafety: ast::Unsafe::Yes(_), .. }, .. }, _, + _, body, ) = fk { diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 7447f9f64b7b1..e7855f8057c7f 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -158,7 +158,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> // Explicitly check for lints associated with 'closure_id', since // it does not have a corresponding AST node - if let ast_visit::FnKind::Fn(_, _, sig, _, _) = fk { + if let ast_visit::FnKind::Fn(_, _, sig, _, _, _) = fk { if let ast::Async::Yes { closure_id, .. } = sig.header.asyncness { self.check_id(closure_id); } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 8ea5dca6f108a..1e8cca6122c4c 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -133,8 +133,10 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> { } fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) { - if let FnKind::Fn(_, _, sig, _, body) = fn_kind { + if let FnKind::Fn(_, _, sig, _, generics, body) = fn_kind { if let Async::Yes { closure_id, return_impl_trait_id, .. } = sig.header.asyncness { + self.visit_generics(generics); + let return_impl_trait_id = self.create_def(return_impl_trait_id, DefPathData::ImplTrait, span); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 2f6ac4020bc65..383ca958e6d4e 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -537,10 +537,12 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { let rib_kind = match fn_kind { // Bail if the function is foreign, and thus cannot validly have // a body, or if there's no body for some other reason. - FnKind::Fn(FnCtxt::Foreign, _, sig, ..) | FnKind::Fn(_, _, sig, .., None) => { + FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _) + | FnKind::Fn(_, _, sig, _, generics, None) => { // We don't need to deal with patterns in parameters, because // they are not possible for foreign or bodiless functions. self.visit_fn_header(&sig.header); + self.visit_generics(generics); visit::walk_fn_decl(self, &sig.decl); return; } @@ -559,6 +561,10 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { self.with_rib(ValueNS, rib_kind, |this| { // Create a label rib for the function. this.with_label_rib(rib_kind, |this| { + if let FnKind::Fn(_, _, _, _, generics, _) = fn_kind { + this.visit_generics(generics); + } + // Add each argument to the rib. this.resolve_params(&declaration.inputs); diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index 92f423bbb6275..ad2502b041840 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -204,12 +204,11 @@ impl<'a> FnSig<'a> { pub(crate) fn from_fn_kind( fn_kind: &'a visit::FnKind<'_>, - generics: &'a ast::Generics, decl: &'a ast::FnDecl, defaultness: ast::Defaultness, ) -> FnSig<'a> { match *fn_kind { - visit::FnKind::Fn(fn_ctxt, _, fn_sig, vis, _) => match fn_ctxt { + visit::FnKind::Fn(fn_ctxt, _, fn_sig, vis, generics, _) => match fn_ctxt { visit::FnCtxt::Assoc(..) => { let mut fn_sig = FnSig::from_method_sig(fn_sig, generics, vis); fn_sig.defaultness = defaultness; @@ -3180,8 +3179,14 @@ impl Rewrite for ast::ForeignItem { let inner_attrs = inner_attributes(&self.attrs); let fn_ctxt = visit::FnCtxt::Foreign; visitor.visit_fn( - visit::FnKind::Fn(fn_ctxt, self.ident, sig, &self.vis, Some(body)), - generics, + visit::FnKind::Fn( + fn_ctxt, + self.ident, + sig, + &self.vis, + generics, + Some(body), + ), &sig.decl, self.span, defaultness, diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs index 3ebfa551d1cbc..1621eb406b10f 100644 --- a/src/tools/rustfmt/src/visitor.rs +++ b/src/tools/rustfmt/src/visitor.rs @@ -382,7 +382,6 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { pub(crate) fn visit_fn( &mut self, fk: visit::FnKind<'_>, - generics: &ast::Generics, fd: &ast::FnDecl, s: Span, defaultness: ast::Defaultness, @@ -391,12 +390,12 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { let indent = self.block_indent; let block; let rewrite = match fk { - visit::FnKind::Fn(_, ident, _, _, Some(ref b)) => { + visit::FnKind::Fn(_, ident, _, _, _, Some(ref b)) => { block = b; self.rewrite_fn_before_block( indent, ident, - &FnSig::from_fn_kind(&fk, generics, fd, defaultness), + &FnSig::from_fn_kind(&fk, fd, defaultness), mk_sp(s.lo(), b.span.lo()), ) } @@ -552,8 +551,14 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { _ => visit::FnCtxt::Foreign, }; self.visit_fn( - visit::FnKind::Fn(fn_ctxt, item.ident, sig, &item.vis, Some(body)), - generics, + visit::FnKind::Fn( + fn_ctxt, + item.ident, + sig, + &item.vis, + generics, + Some(body), + ), &sig.decl, item.span, defaultness, @@ -642,8 +647,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { let inner_attrs = inner_attributes(&ai.attrs); let fn_ctxt = visit::FnCtxt::Assoc(assoc_ctxt); self.visit_fn( - visit::FnKind::Fn(fn_ctxt, ai.ident, sig, &ai.vis, Some(body)), - generics, + visit::FnKind::Fn(fn_ctxt, ai.ident, sig, &ai.vis, generics, Some(body)), &sig.decl, ai.span, defaultness, From 4cfceeabdcd185cd4bfca080d39e93abddc4977a Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Fri, 11 Mar 2022 12:01:20 +0100 Subject: [PATCH 3/8] Remove is_in_fn_syntax. --- compiler/rustc_resolve/src/late/lifetimes.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 2bf01146fae02..1aa1d51e2efc8 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -164,9 +164,6 @@ crate struct LifetimeContext<'a, 'tcx> { map: &'a mut NamedRegionMap, scope: ScopeRef<'a>, - /// Used to disallow the use of in-band lifetimes in `fn` or `Fn` syntax. - is_in_fn_syntax: bool, - is_in_const_generic: bool, /// Indicates that we only care about the definition of a trait. This should @@ -455,7 +452,6 @@ fn do_resolve( tcx, map: &mut named_region_map, scope: ROOT_SCOPE, - is_in_fn_syntax: false, is_in_const_generic: false, trait_definition_only, labels_in_fn: vec![], @@ -874,8 +870,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { match ty.kind { hir::TyKind::BareFn(ref c) => { let next_early_index = self.next_early_index(); - let was_in_fn_syntax = self.is_in_fn_syntax; - self.is_in_fn_syntax = true; let lifetime_span: Option = c.generic_params.iter().rev().find_map(|param| match param.kind { GenericParamKind::Lifetime { .. } => Some(param.span), @@ -917,7 +911,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { intravisit::walk_ty(this, ty); }); self.missing_named_lifetime_spots.pop(); - self.is_in_fn_syntax = was_in_fn_syntax; } hir::TyKind::TraitObject(bounds, ref lifetime, _) => { debug!(?bounds, ?lifetime, "TraitObject"); @@ -1805,7 +1798,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { tcx: *tcx, map, scope: &wrap_scope, - is_in_fn_syntax: self.is_in_fn_syntax, is_in_const_generic: self.is_in_const_generic, trait_definition_only: self.trait_definition_only, labels_in_fn, @@ -2336,10 +2328,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { ); if generic_args.parenthesized { - let was_in_fn_syntax = self.is_in_fn_syntax; - self.is_in_fn_syntax = true; self.visit_fn_like_elision(generic_args.inputs(), Some(generic_args.bindings[0].ty())); - self.is_in_fn_syntax = was_in_fn_syntax; return; } From fc9f25531a3681f0644267eb954d51f4b22ff5b7 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 6 Mar 2022 12:02:13 +0100 Subject: [PATCH 4/8] Report undeclared lifetimes on AST. --- compiler/rustc_ast_lowering/src/lib.rs | 25 +- compiler/rustc_resolve/src/late.rs | 1024 ++++++++++++----- .../rustc_resolve/src/late/diagnostics.rs | 156 ++- compiler/rustc_resolve/src/late/lifetimes.rs | 17 +- compiler/rustc_resolve/src/lib.rs | 15 +- 5 files changed, 837 insertions(+), 400 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index e7e82e651bb09..5f465124a3168 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -484,7 +484,7 @@ enum ParenthesizedGenericArgs { /// an "elided" or "underscore" lifetime name. In the future, we probably want to move /// everything into HIR lowering. #[derive(Copy, Clone, Debug)] -enum AnonymousLifetimeMode { +pub enum AnonymousLifetimeMode { /// For **Modern** cases, create a new anonymous region parameter /// and reference that. /// @@ -2017,16 +2017,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }); let param_name = match lt.name { hir::LifetimeName::Param(param_name) => param_name, - hir::LifetimeName::Implicit(_) - | hir::LifetimeName::Underscore - | hir::LifetimeName::Static => hir::ParamName::Plain(lt.name.ident()), + hir::LifetimeName::Implicit(_) | hir::LifetimeName::Underscore => { + hir::ParamName::Plain(lt.name.ident()) + } hir::LifetimeName::ImplicitObjectLifetimeDefault => { self.sess.diagnostic().span_bug( param.ident.span, "object-lifetime-default should not occur here", ); } - hir::LifetimeName::Error => ParamName::Error, + hir::LifetimeName::Static | hir::LifetimeName::Error => ParamName::Error, }; let kind = @@ -2404,20 +2404,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// Report an error on illegal use of `'_` or a `&T` with no explicit lifetime; /// return an "error lifetime". fn new_error_lifetime(&mut self, id: Option, span: Span) -> hir::Lifetime { - let (id, msg, label) = match id { - Some(id) => (id, "`'_` cannot be used here", "`'_` is a reserved lifetime name"), - - None => ( - self.resolver.next_node_id(), - "`&` without an explicit lifetime name cannot be used here", - "explicit lifetime name needed here", - ), - }; - - let mut err = struct_span_err!(self.sess, span, E0637, "{}", msg,); - err.span_label(span, label); - err.emit(); - + let id = id.unwrap_or_else(|| self.resolver.next_node_id()); self.new_named_lifetime(id, span, hir::LifetimeName::Error) } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 383ca958e6d4e..c6cebd1d3b134 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -188,6 +188,68 @@ impl<'a, R> Rib<'a, R> { } } +#[derive(Copy, Clone, Debug)] +enum LifetimeRibKind { + /// This rib acts as a barrier to forbid reference to lifetimes of a parent item. + Item, + + /// This rib declares generic parameters. + Generics { span: Span, kind: LifetimeBinderKind }, + + /// For **Modern** cases, create a new anonymous region parameter + /// and reference that. + /// + /// For **Dyn Bound** cases, pass responsibility to + /// `resolve_lifetime` code. + /// + /// For **Deprecated** cases, report an error. + AnonymousCreateParameter, + + /// Give a hard error when either `&` or `'_` is written. Used to + /// rule out things like `where T: Foo<'_>`. Does not imply an + /// error on default object bounds (e.g., `Box`). + AnonymousReportError, + + /// Pass responsibility to `resolve_lifetime` code for all cases. + AnonymousPassThrough, +} + +#[derive(Copy, Clone, Debug)] +enum LifetimeBinderKind { + BareFnType, + PolyTrait, + WhereBound, + Item, + Function, + ImplBlock, +} + +impl LifetimeBinderKind { + fn descr(self) -> &'static str { + use LifetimeBinderKind::*; + match self { + BareFnType => "type", + PolyTrait => "bound", + WhereBound => "bound", + Item => "item", + ImplBlock => "impl block", + Function => "function", + } + } +} + +#[derive(Debug)] +struct LifetimeRib { + kind: LifetimeRibKind, + bindings: IdentMap<()>, +} + +impl LifetimeRib { + fn new(kind: LifetimeRibKind) -> LifetimeRib { + LifetimeRib { bindings: Default::default(), kind } + } +} + #[derive(Copy, Clone, PartialEq, Eq, Debug)] crate enum AliasPossibility { No, @@ -422,6 +484,9 @@ struct LateResolutionVisitor<'a, 'b, 'ast> { /// The current set of local scopes, for labels. label_ribs: Vec>, + /// The current set of local scopes for lifetimes. + lifetime_ribs: Vec, + /// The trait that the current context can refer to. current_trait_ref: Option<(Module<'a>, TraitRef)>, @@ -446,7 +511,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { let prev = replace(&mut self.diagnostic_metadata.current_item, Some(item)); // Always report errors in items we just entered. let old_ignore = replace(&mut self.in_func_body, false); - self.resolve_item(item); + self.with_lifetime_rib(LifetimeRibKind::Item, |this| this.resolve_item(item)); self.in_func_body = old_ignore; self.diagnostic_metadata.current_item = prev; } @@ -481,6 +546,12 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { let prev = self.diagnostic_metadata.current_trait_object; let prev_ty = self.diagnostic_metadata.current_type_path; match ty.kind { + TyKind::Rptr(None, _) => { + // Elided lifetime in reference: we resolve as if there was some lifetime `'_` with + // NodeId `ty.id`. + let span = self.r.session.source_map().next_point(ty.span.shrink_to_lo()); + self.resolve_elided_lifetime(ty.id, span); + } TyKind::Path(ref qself, ref path) => { self.diagnostic_metadata.current_type_path = Some(ty); self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type); @@ -500,36 +571,86 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { TyKind::TraitObject(ref bounds, ..) => { self.diagnostic_metadata.current_trait_object = Some(&bounds[..]); } + TyKind::BareFn(ref bare_fn) => { + let span = if bare_fn.generic_params.is_empty() { + ty.span.shrink_to_lo() + } else { + ty.span + }; + self.with_generic_param_rib( + &bare_fn.generic_params, + NormalRibKind, + LifetimeRibKind::Generics { kind: LifetimeBinderKind::BareFnType, span }, + |this| { + this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| { + this.visit_generic_param_vec(&bare_fn.generic_params, false); + visit::walk_fn_decl(this, &bare_fn.decl); + }); + }, + ); + self.diagnostic_metadata.current_trait_object = prev; + return; + } _ => (), } visit::walk_ty(self, ty); self.diagnostic_metadata.current_trait_object = prev; self.diagnostic_metadata.current_type_path = prev_ty; } - fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) { - self.smart_resolve_path( - tref.trait_ref.ref_id, - None, - &tref.trait_ref.path, - PathSource::Trait(AliasPossibility::Maybe), + fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef, _: &'ast TraitBoundModifier) { + let span = + if tref.bound_generic_params.is_empty() { tref.span.shrink_to_lo() } else { tref.span }; + self.with_generic_param_rib( + &tref.bound_generic_params, + NormalRibKind, + LifetimeRibKind::Generics { kind: LifetimeBinderKind::PolyTrait, span }, + |this| { + this.visit_generic_param_vec(&tref.bound_generic_params, false); + this.smart_resolve_path( + tref.trait_ref.ref_id, + None, + &tref.trait_ref.path, + PathSource::Trait(AliasPossibility::Maybe), + ); + this.visit_trait_ref(&tref.trait_ref); + }, ); - visit::walk_poly_trait_ref(self, tref, m); } fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) { match foreign_item.kind { - ForeignItemKind::Fn(box Fn { ref generics, .. }) - | ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => { - self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { - visit::walk_foreign_item(this, foreign_item); + ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => { + self.with_lifetime_rib(LifetimeRibKind::Item, |this| { + this.with_generic_param_rib( + &generics.params, + ItemRibKind(HasGenericParams::Yes), + LifetimeRibKind::Generics { + kind: LifetimeBinderKind::Item, + span: generics.span, + }, + |this| visit::walk_foreign_item(this, foreign_item), + ) + }); + } + ForeignItemKind::Fn(box Fn { ref generics, .. }) => { + self.with_lifetime_rib(LifetimeRibKind::Item, |this| { + this.with_generic_param_rib( + &generics.params, + ItemRibKind(HasGenericParams::Yes), + LifetimeRibKind::Generics { + kind: LifetimeBinderKind::Function, + span: generics.span, + }, + |this| visit::walk_foreign_item(this, foreign_item), + ) }); } ForeignItemKind::Static(..) => { - self.with_item_rib(HasGenericParams::No, |this| { + self.with_item_rib(|this| { visit::walk_foreign_item(this, foreign_item); }); } ForeignItemKind::MacCall(..) => { - visit::walk_foreign_item(self, foreign_item); + panic!("unexpanded macro in resolve!") } } } @@ -539,11 +660,13 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { // a body, or if there's no body for some other reason. FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _) | FnKind::Fn(_, _, sig, _, generics, None) => { - // We don't need to deal with patterns in parameters, because - // they are not possible for foreign or bodiless functions. - self.visit_fn_header(&sig.header); - self.visit_generics(generics); - visit::walk_fn_decl(self, &sig.decl); + self.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| { + // We don't need to deal with patterns in parameters, because + // they are not possible for foreign or bodiless functions. + this.visit_fn_header(&sig.header); + this.visit_generics(generics); + visit::walk_fn_decl(this, &sig.decl); + }); return; } FnKind::Fn(FnCtxt::Free, ..) => FnItemRibKind, @@ -561,23 +684,44 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { self.with_rib(ValueNS, rib_kind, |this| { // Create a label rib for the function. this.with_label_rib(rib_kind, |this| { + let async_node_id = fn_kind.header().and_then(|h| h.asyncness.opt_return_id()); + if let FnKind::Fn(_, _, _, _, generics, _) = fn_kind { this.visit_generics(generics); } - // Add each argument to the rib. - this.resolve_params(&declaration.inputs); + if async_node_id.is_some() { + // In `async fn`, argument-position elided lifetimes + // must be transformed into fresh generic parameters so that + // they can be applied to the opaque `impl Trait` return type. + this.with_lifetime_rib(LifetimeRibKind::AnonymousCreateParameter, |this| { + // Add each argument to the rib. + this.resolve_params(&declaration.inputs) + }); - visit::walk_fn_ret_ty(this, &declaration.output); + this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| { + visit::walk_fn_ret_ty(this, &declaration.output) + }); + } else { + this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| { + // Add each argument to the rib. + this.resolve_params(&declaration.inputs); + + visit::walk_fn_ret_ty(this, &declaration.output); + }); + }; // Ignore errors in function bodies if this is rustdoc // Be sure not to set this until the function signature has been resolved. let previous_state = replace(&mut this.in_func_body, true); // Resolve the function body, potentially inside the body of an async closure - match fn_kind { - FnKind::Fn(.., body) => walk_list!(this, visit_block, body), - FnKind::Closure(_, body) => this.visit_expr(body), - }; + this.with_lifetime_rib( + LifetimeRibKind::AnonymousPassThrough, + |this| match fn_kind { + FnKind::Fn(.., body) => walk_list!(this, visit_block, body), + FnKind::Closure(_, body) => this.visit_expr(body), + }, + ); debug!("(resolving function) leaving function"); this.in_func_body = previous_state; @@ -585,89 +729,15 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { }); self.diagnostic_metadata.current_function = previous_value; } + fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) { + self.resolve_lifetime(lifetime) + } fn visit_generics(&mut self, generics: &'ast Generics) { - // For type parameter defaults, we have to ban access - // to following type parameters, as the InternalSubsts can only - // provide previous type parameters as they're built. We - // put all the parameters on the ban list and then remove - // them one by one as they are processed and become available. - let mut forward_ty_ban_rib = Rib::new(ForwardGenericParamBanRibKind); - let mut forward_const_ban_rib = Rib::new(ForwardGenericParamBanRibKind); - for param in generics.params.iter() { - match param.kind { - GenericParamKind::Type { .. } => { - forward_ty_ban_rib - .bindings - .insert(Ident::with_dummy_span(param.ident.name), Res::Err); - } - GenericParamKind::Const { .. } => { - forward_const_ban_rib - .bindings - .insert(Ident::with_dummy_span(param.ident.name), Res::Err); - } - GenericParamKind::Lifetime => {} - } - } - - // rust-lang/rust#61631: The type `Self` is essentially - // another type parameter. For ADTs, we consider it - // well-defined only after all of the ADT type parameters have - // been provided. Therefore, we do not allow use of `Self` - // anywhere in ADT type parameter defaults. - // - // (We however cannot ban `Self` for defaults on *all* generic - // lists; e.g. trait generics can usefully refer to `Self`, - // such as in the case of `trait Add`.) - if self.diagnostic_metadata.current_self_item.is_some() { - // (`Some` if + only if we are in ADT's generics.) - forward_ty_ban_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), Res::Err); - } - - for param in &generics.params { - match param.kind { - GenericParamKind::Lifetime => self.visit_generic_param(param), - GenericParamKind::Type { ref default } => { - for bound in ¶m.bounds { - self.visit_param_bound(bound); - } - - if let Some(ref ty) = default { - self.ribs[TypeNS].push(forward_ty_ban_rib); - self.ribs[ValueNS].push(forward_const_ban_rib); - self.visit_ty(ty); - forward_const_ban_rib = self.ribs[ValueNS].pop().unwrap(); - forward_ty_ban_rib = self.ribs[TypeNS].pop().unwrap(); - } - - // Allow all following defaults to refer to this type parameter. - forward_ty_ban_rib.bindings.remove(&Ident::with_dummy_span(param.ident.name)); - } - GenericParamKind::Const { ref ty, kw_span: _, ref default } => { - // Const parameters can't have param bounds. - assert!(param.bounds.is_empty()); - - self.ribs[TypeNS].push(Rib::new(ConstParamTyRibKind)); - self.ribs[ValueNS].push(Rib::new(ConstParamTyRibKind)); - self.visit_ty(ty); - self.ribs[TypeNS].pop().unwrap(); - self.ribs[ValueNS].pop().unwrap(); - - if let Some(ref expr) = default { - self.ribs[TypeNS].push(forward_ty_ban_rib); - self.ribs[ValueNS].push(forward_const_ban_rib); - self.visit_anon_const(expr); - forward_const_ban_rib = self.ribs[ValueNS].pop().unwrap(); - forward_ty_ban_rib = self.ribs[TypeNS].pop().unwrap(); - } - - // Allow all following defaults to refer to this const parameter. - forward_const_ban_rib - .bindings - .remove(&Ident::with_dummy_span(param.ident.name)); - } - } - } + self.visit_generic_param_vec( + &generics.params, + self.diagnostic_metadata.current_self_item.is_some(), + ); for p in &generics.where_clause.predicates { self.visit_where_predicate(p); } @@ -726,11 +796,52 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { self.diagnostic_metadata.currently_processing_generics = prev; } + fn visit_path_segment(&mut self, path_span: Span, path_segment: &'ast PathSegment) { + if let Some(ref args) = path_segment.args { + match &**args { + GenericArgs::AngleBracketed(..) => visit::walk_generic_args(self, path_span, args), + GenericArgs::Parenthesized(..) => self + .with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| { + visit::walk_generic_args(this, path_span, args) + }), + } + } + } + fn visit_where_predicate(&mut self, p: &'ast WherePredicate) { debug!("visit_where_predicate {:?}", p); let previous_value = replace(&mut self.diagnostic_metadata.current_where_predicate, Some(p)); - visit::walk_where_predicate(self, p); + self.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| { + if let WherePredicate::BoundPredicate(WhereBoundPredicate { + ref bounded_ty, + ref bounds, + ref bound_generic_params, + span: predicate_span, + .. + }) = p + { + let span = if bound_generic_params.is_empty() { + predicate_span.shrink_to_lo() + } else { + *predicate_span + }; + this.with_generic_param_rib( + &bound_generic_params, + NormalRibKind, + LifetimeRibKind::Generics { kind: LifetimeBinderKind::WhereBound, span }, + |this| { + this.visit_generic_param_vec(&bound_generic_params, false); + this.visit_ty(bounded_ty); + for bound in bounds { + this.visit_param_bound(bound) + } + }, + ); + } else { + visit::walk_where_predicate(this, p); + } + }); self.diagnostic_metadata.current_where_predicate = previous_value; } @@ -768,6 +879,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { macro_ns: vec![Rib::new(start_rib_kind)], }, label_ribs: Vec::new(), + lifetime_ribs: Vec::new(), current_trait_ref: None, diagnostic_metadata: DiagnosticMetadata::default(), // errors at module scope should always be reported @@ -870,6 +982,191 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } } + fn visit_generic_param_vec(&mut self, params: &'ast Vec, add_self_upper: bool) { + // For type parameter defaults, we have to ban access + // to following type parameters, as the InternalSubsts can only + // provide previous type parameters as they're built. We + // put all the parameters on the ban list and then remove + // them one by one as they are processed and become available. + let mut forward_ty_ban_rib = Rib::new(ForwardGenericParamBanRibKind); + let mut forward_const_ban_rib = Rib::new(ForwardGenericParamBanRibKind); + for param in params.iter() { + match param.kind { + GenericParamKind::Type { .. } => { + forward_ty_ban_rib + .bindings + .insert(Ident::with_dummy_span(param.ident.name), Res::Err); + } + GenericParamKind::Const { .. } => { + forward_const_ban_rib + .bindings + .insert(Ident::with_dummy_span(param.ident.name), Res::Err); + } + GenericParamKind::Lifetime => {} + } + } + + // rust-lang/rust#61631: The type `Self` is essentially + // another type parameter. For ADTs, we consider it + // well-defined only after all of the ADT type parameters have + // been provided. Therefore, we do not allow use of `Self` + // anywhere in ADT type parameter defaults. + // + // (We however cannot ban `Self` for defaults on *all* generic + // lists; e.g. trait generics can usefully refer to `Self`, + // such as in the case of `trait Add`.) + if add_self_upper { + // (`Some` if + only if we are in ADT's generics.) + forward_ty_ban_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), Res::Err); + } + + self.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| { + for param in params { + match param.kind { + GenericParamKind::Lifetime => { + for bound in ¶m.bounds { + this.visit_param_bound(bound); + } + } + GenericParamKind::Type { ref default } => { + for bound in ¶m.bounds { + this.visit_param_bound(bound); + } + + if let Some(ref ty) = default { + this.ribs[TypeNS].push(forward_ty_ban_rib); + this.ribs[ValueNS].push(forward_const_ban_rib); + this.visit_ty(ty); + forward_const_ban_rib = this.ribs[ValueNS].pop().unwrap(); + forward_ty_ban_rib = this.ribs[TypeNS].pop().unwrap(); + } + + // Allow all following defaults to refer to this type parameter. + forward_ty_ban_rib + .bindings + .remove(&Ident::with_dummy_span(param.ident.name)); + } + GenericParamKind::Const { ref ty, kw_span: _, ref default } => { + // Const parameters can't have param bounds. + assert!(param.bounds.is_empty()); + + this.ribs[TypeNS].push(Rib::new(ConstParamTyRibKind)); + this.ribs[ValueNS].push(Rib::new(ConstParamTyRibKind)); + this.visit_ty(ty); + this.ribs[TypeNS].pop().unwrap(); + this.ribs[ValueNS].pop().unwrap(); + + if let Some(ref expr) = default { + this.ribs[TypeNS].push(forward_ty_ban_rib); + this.ribs[ValueNS].push(forward_const_ban_rib); + this.visit_anon_const(expr); + forward_const_ban_rib = this.ribs[ValueNS].pop().unwrap(); + forward_ty_ban_rib = this.ribs[TypeNS].pop().unwrap(); + } + + // Allow all following defaults to refer to this const parameter. + forward_const_ban_rib + .bindings + .remove(&Ident::with_dummy_span(param.ident.name)); + } + } + } + }) + } + + #[tracing::instrument(level = "debug", skip(self, work))] + fn with_lifetime_rib( + &mut self, + kind: LifetimeRibKind, + work: impl FnOnce(&mut Self) -> T, + ) -> T { + self.lifetime_ribs.push(LifetimeRib::new(kind)); + let ret = work(self); + self.lifetime_ribs.pop(); + ret + } + + #[tracing::instrument(level = "debug", skip(self))] + fn resolve_lifetime(&mut self, lifetime: &'ast Lifetime) { + let ident = lifetime.ident; + + if ident.name == kw::StaticLifetime { + return; + } + + if ident.name == kw::UnderscoreLifetime { + return self.resolve_anonymous_lifetime(lifetime, false); + } + + let mut indices = (0..self.lifetime_ribs.len()).rev(); + for i in &mut indices { + let rib = &self.lifetime_ribs[i]; + let normalized_ident = ident.normalize_to_macros_2_0(); + if let Some(_) = rib.bindings.get_key_value(&normalized_ident) { + return; + } + + if let LifetimeRibKind::Item = rib.kind { + break; + } + } + + let mut outer_res = None; + for i in indices { + let rib = &self.lifetime_ribs[i]; + let normalized_ident = ident.normalize_to_macros_2_0(); + if let Some((&outer, _)) = rib.bindings.get_key_value(&normalized_ident) { + outer_res = Some(outer); + break; + } + } + + self.emit_undeclared_lifetime_error(lifetime, outer_res); + } + + #[tracing::instrument(level = "debug", skip(self))] + fn resolve_anonymous_lifetime(&mut self, lifetime: &Lifetime, elided: bool) { + debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime); + + for i in (0..self.lifetime_ribs.len()).rev() { + let rib = &mut self.lifetime_ribs[i]; + match rib.kind { + LifetimeRibKind::AnonymousReportError => { + let (msg, note) = if elided { + ( + "`&` without an explicit lifetime name cannot be used here", + "explicit lifetime name needed here", + ) + } else { + ("`'_` cannot be used here", "`'_` is a reserved lifetime name") + }; + rustc_errors::struct_span_err!( + self.r.session, + lifetime.ident.span, + E0637, + "{}", + msg, + ) + .span_label(lifetime.ident.span, note) + .emit(); + + return; + } + LifetimeRibKind::AnonymousCreateParameter + | LifetimeRibKind::AnonymousPassThrough + | LifetimeRibKind::Item => return, + _ => {} + } + } + } + + #[tracing::instrument(level = "debug", skip(self))] + fn resolve_elided_lifetime(&mut self, anchor_id: NodeId, span: Span) { + let id = self.r.next_node_id(); + let lt = Lifetime { id, ident: Ident::new(kw::UnderscoreLifetime, span) }; + self.resolve_anonymous_lifetime(<, true); + } + /// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved /// label and reports an error if the label is not found or is unreachable. fn resolve_label(&self, mut label: Ident) -> Option { @@ -950,15 +1247,20 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { fn resolve_adt(&mut self, item: &'ast Item, generics: &'ast Generics) { debug!("resolve_adt"); self.with_current_self_item(item, |this| { - this.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { - let item_def_id = this.r.local_def_id(item.id).to_def_id(); - this.with_self_rib( - Res::SelfTy { trait_: None, alias_to: Some((item_def_id, false)) }, - |this| { - visit::walk_item(this, item); - }, - ); - }); + this.with_generic_param_rib( + &generics.params, + ItemRibKind(HasGenericParams::Yes), + LifetimeRibKind::Generics { kind: LifetimeBinderKind::Item, span: generics.span }, + |this| { + let item_def_id = this.r.local_def_id(item.id).to_def_id(); + this.with_self_rib( + Res::SelfTy { trait_: None, alias_to: Some((item_def_id, false)) }, + |this| { + visit::walk_item(this, item); + }, + ); + }, + ); }); } @@ -1010,11 +1312,28 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { debug!("(resolving item) resolving {} ({:?})", name, item.kind); match item.kind { - ItemKind::TyAlias(box TyAlias { ref generics, .. }) - | ItemKind::Fn(box Fn { ref generics, .. }) => { - self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { - visit::walk_item(this, item) - }); + ItemKind::TyAlias(box TyAlias { ref generics, .. }) => { + self.with_generic_param_rib( + &generics.params, + ItemRibKind(HasGenericParams::Yes), + LifetimeRibKind::Generics { + kind: LifetimeBinderKind::Item, + span: generics.span, + }, + |this| visit::walk_item(this, item), + ); + } + + ItemKind::Fn(box Fn { ref generics, .. }) => { + self.with_generic_param_rib( + &generics.params, + ItemRibKind(HasGenericParams::Yes), + LifetimeRibKind::Generics { + kind: LifetimeBinderKind::Function, + span: generics.span, + }, + |this| visit::walk_item(this, item), + ); } ItemKind::Enum(_, ref generics) @@ -1035,64 +1354,108 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ItemKind::Trait(box Trait { ref generics, ref bounds, ref items, .. }) => { // Create a new rib for the trait-wide type parameters. - self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { - let def = this.r.local_def_id(item.id).to_def_id(); - this.with_self_rib(Res::SelfTy { trait_: Some(def), alias_to: None }, |this| { - this.visit_generics(generics); - walk_list!(this, visit_param_bound, bounds); - - let walk_assoc_item = |this: &mut Self, generics, item| { - this.with_generic_param_rib(generics, AssocItemRibKind, |this| { - visit::walk_assoc_item(this, item, AssocCtxt::Trait) - }); - }; - - this.with_trait_items(items, |this| { - for item in items { - match &item.kind { - AssocItemKind::Const(_, ty, default) => { - this.visit_ty(ty); - // Only impose the restrictions of `ConstRibKind` for an - // actual constant expression in a provided default. - if let Some(expr) = default { - // We allow arbitrary const expressions inside of associated consts, - // even if they are potentially not const evaluatable. - // - // Type parameters can already be used and as associated consts are - // not used as part of the type system, this is far less surprising. - this.with_constant_rib( - IsRepeatExpr::No, - true, - None, - |this| this.visit_expr(expr), - ); - } - } - AssocItemKind::Fn(box Fn { generics, .. }) => { - walk_assoc_item(this, generics, item); - } - AssocItemKind::TyAlias(box TyAlias { generics, .. }) => { - walk_assoc_item(this, generics, item); - } - AssocItemKind::MacCall(_) => { - panic!("unexpanded macro in resolve!") + self.with_generic_param_rib( + &generics.params, + ItemRibKind(HasGenericParams::Yes), + LifetimeRibKind::Generics { + kind: LifetimeBinderKind::Item, + span: generics.span, + }, + |this| { + let local_def_id = this.r.local_def_id(item.id).to_def_id(); + this.with_self_rib( + Res::SelfTy { trait_: Some(local_def_id), alias_to: None }, + |this| { + this.visit_generics(generics); + walk_list!(this, visit_param_bound, bounds); + + let walk_assoc_item = + |this: &mut Self, + generics: &Generics, + kind, + item: &'ast AssocItem| { + this.with_generic_param_rib( + &generics.params, + AssocItemRibKind, + LifetimeRibKind::Generics { span: generics.span, kind }, + |this| { + visit::walk_assoc_item(this, item, AssocCtxt::Trait) + }, + ); + }; + + this.with_trait_items(items, |this| { + for item in items { + match &item.kind { + AssocItemKind::Const(_, ty, default) => { + this.visit_ty(ty); + // Only impose the restrictions of `ConstRibKind` for an + // actual constant expression in a provided default. + if let Some(expr) = default { + // We allow arbitrary const expressions inside of associated consts, + // even if they are potentially not const evaluatable. + // + // Type parameters can already be used and as associated consts are + // not used as part of the type system, this is far less surprising. + this.with_constant_rib( + IsRepeatExpr::No, + true, + None, + |this| this.visit_expr(expr), + ); + } + } + AssocItemKind::Fn(box Fn { generics, .. }) => { + walk_assoc_item( + this, + generics, + LifetimeBinderKind::Function, + item, + ); + } + AssocItemKind::TyAlias(box TyAlias { + generics, + .. + }) => { + walk_assoc_item( + this, + generics, + LifetimeBinderKind::Item, + item, + ); + } + AssocItemKind::MacCall(_) => { + panic!("unexpanded macro in resolve!") + } + }; } - }; - } - }); - }); - }); + }); + }, + ); + }, + ); } ItemKind::TraitAlias(ref generics, ref bounds) => { // Create a new rib for the trait-wide type parameters. - self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { - let def = this.r.local_def_id(item.id).to_def_id(); - this.with_self_rib(Res::SelfTy { trait_: Some(def), alias_to: None }, |this| { - this.visit_generics(generics); - walk_list!(this, visit_param_bound, bounds); - }); - }); + self.with_generic_param_rib( + &generics.params, + ItemRibKind(HasGenericParams::Yes), + LifetimeRibKind::Generics { + kind: LifetimeBinderKind::Item, + span: generics.span, + }, + |this| { + let local_def_id = this.r.local_def_id(item.id).to_def_id(); + this.with_self_rib( + Res::SelfTy { trait_: Some(local_def_id), alias_to: None }, + |this| { + this.visit_generics(generics); + walk_list!(this, visit_param_bound, bounds); + }, + ); + }, + ); } ItemKind::Mod(..) | ItemKind::ForeignMod(_) => { @@ -1102,7 +1465,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } ItemKind::Static(ref ty, _, ref expr) | ItemKind::Const(_, ref ty, ref expr) => { - self.with_item_rib(HasGenericParams::No, |this| { + self.with_item_rib(|this| { this.visit_ty(ty); if let Some(expr) = expr { let constant_item_kind = match item.kind { @@ -1138,13 +1501,19 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } } - fn with_generic_param_rib<'c, F>(&'c mut self, generics: &'c Generics, kind: RibKind<'a>, f: F) - where + fn with_generic_param_rib<'c, F>( + &'c mut self, + params: &'c Vec, + kind: RibKind<'a>, + lifetime_kind: LifetimeRibKind, + f: F, + ) where F: FnOnce(&mut Self), { debug!("with_generic_param_rib"); let mut function_type_rib = Rib::new(kind); let mut function_value_rib = Rib::new(kind); + let mut function_lifetime_rib = LifetimeRib::new(lifetime_kind); let mut seen_bindings = FxHashMap::default(); // We also can't shadow bindings from the parent item @@ -1161,11 +1530,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { add_bindings_for_ns(TypeNS); } - for param in &generics.params { - if let GenericParamKind::Lifetime = param.kind { - continue; - } - + for param in params { let ident = param.ident.normalize_to_macros_2_0(); debug!("with_generic_param_rib: {}", param.id); @@ -1173,24 +1538,57 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { Entry::Occupied(entry) => { let span = *entry.get(); let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, span); - self.report_error(param.ident.span, err); + if !matches!(param.kind, GenericParamKind::Lifetime) { + self.report_error(param.ident.span, err); + } } Entry::Vacant(entry) => { entry.insert(param.ident.span); } } + if param.ident.name == kw::UnderscoreLifetime { + rustc_errors::struct_span_err!( + self.r.session, + param.ident.span, + E0637, + "`'_` cannot be used here" + ) + .span_label(param.ident.span, "`'_` is a reserved lifetime name") + .emit(); + continue; + } + + if param.ident.name == kw::StaticLifetime { + rustc_errors::struct_span_err!( + self.r.session, + param.ident.span, + E0262, + "invalid lifetime parameter name: `{}`", + param.ident, + ) + .span_label(param.ident.span, format!("'static is a reserved lifetime name")) + .emit(); + continue; + } + + let def_id = self.r.local_def_id(param.id); + // Plain insert (no renaming). let (rib, def_kind) = match param.kind { GenericParamKind::Type { .. } => (&mut function_type_rib, DefKind::TyParam), GenericParamKind::Const { .. } => (&mut function_value_rib, DefKind::ConstParam), - _ => unreachable!(), + GenericParamKind::Lifetime => { + function_lifetime_rib.bindings.insert(ident, ()); + continue; + } }; - let res = Res::Def(def_kind, self.r.local_def_id(param.id).to_def_id()); + let res = Res::Def(def_kind, def_id.to_def_id()); self.r.record_partial_res(param.id, PartialRes::new(res)); rib.bindings.insert(ident, res); } + self.lifetime_ribs.push(function_lifetime_rib); self.ribs[ValueNS].push(function_value_rib); self.ribs[TypeNS].push(function_type_rib); @@ -1198,6 +1596,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.ribs[TypeNS].pop(); self.ribs[ValueNS].pop(); + self.lifetime_ribs.pop(); } fn with_label_rib(&mut self, kind: RibKind<'a>, f: impl FnOnce(&mut Self)) { @@ -1206,9 +1605,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.label_ribs.pop(); } - fn with_item_rib(&mut self, has_generic_params: HasGenericParams, f: impl FnOnce(&mut Self)) { - let kind = ItemRibKind(has_generic_params); - self.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f)) + fn with_item_rib(&mut self, f: impl FnOnce(&mut Self)) { + let kind = ItemRibKind(HasGenericParams::No); + self.with_lifetime_rib(LifetimeRibKind::Item, |this| { + this.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f)) + }) } // HACK(min_const_generics,const_evaluatable_unchecked): We @@ -1319,128 +1720,137 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ) { debug!("resolve_implementation"); // If applicable, create a rib for the type parameters. - self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { + self.with_generic_param_rib(&generics.params, ItemRibKind(HasGenericParams::Yes), LifetimeRibKind::Generics { span: generics.span, kind: LifetimeBinderKind::ImplBlock }, |this| { // Dummy self type for better errors if `Self` is used in the trait path. this.with_self_rib(Res::SelfTy { trait_: None, alias_to: None }, |this| { - // Resolve the trait reference, if necessary. - this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| { - let item_def_id = this.r.local_def_id(item_id); - - // Register the trait definitions from here. - if let Some(trait_id) = trait_id { - this.r.trait_impls.entry(trait_id).or_default().push(item_def_id); - } - - let item_def_id = item_def_id.to_def_id(); - let res = - Res::SelfTy { trait_: trait_id, alias_to: Some((item_def_id, false)) }; - this.with_self_rib(res, |this| { - if let Some(trait_ref) = opt_trait_reference.as_ref() { - // Resolve type arguments in the trait path. - visit::walk_trait_ref(this, trait_ref); + this.with_lifetime_rib(LifetimeRibKind::AnonymousCreateParameter, |this| { + // Resolve the trait reference, if necessary. + this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| { + let item_def_id = this.r.local_def_id(item_id); + + // Register the trait definitions from here. + if let Some(trait_id) = trait_id { + this.r.trait_impls.entry(trait_id).or_default().push(item_def_id); } - // Resolve the self type. - this.visit_ty(self_type); - // Resolve the generic parameters. - this.visit_generics(generics); - // Resolve the items within the impl. - this.with_current_self_type(self_type, |this| { - this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| { - debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)"); - for item in impl_items { - use crate::ResolutionError::*; - match &item.kind { - AssocItemKind::Const(_default, _ty, _expr) => { - debug!("resolve_implementation AssocItemKind::Const"); - // If this is a trait impl, ensure the const - // exists in trait - this.check_trait_item( - item.id, - item.ident, - &item.kind, - ValueNS, - item.span, - |i, s, c| ConstNotMemberOfTrait(i, s, c), - ); - - // We allow arbitrary const expressions inside of associated consts, - // even if they are potentially not const evaluatable. - // - // Type parameters can already be used and as associated consts are - // not used as part of the type system, this is far less surprising. - this.with_constant_rib( - IsRepeatExpr::No, - true, - None, - |this| { - visit::walk_assoc_item( - this, - item, - AssocCtxt::Impl, - ) - }, - ); - } - AssocItemKind::Fn(box Fn { generics, .. }) => { - debug!("resolve_implementation AssocItemKind::Fn"); - // We also need a new scope for the impl item type parameters. - this.with_generic_param_rib( - generics, - AssocItemRibKind, - |this| { - // If this is a trait impl, ensure the method - // exists in trait - this.check_trait_item( - item.id, - item.ident, - &item.kind, - ValueNS, - item.span, - |i, s, c| MethodNotMemberOfTrait(i, s, c), - ); - - visit::walk_assoc_item( - this, - item, - AssocCtxt::Impl, - ) - }, - ); - } - AssocItemKind::TyAlias(box TyAlias { - generics, .. - }) => { - debug!("resolve_implementation AssocItemKind::TyAlias"); - // We also need a new scope for the impl item type parameters. - this.with_generic_param_rib( - generics, - AssocItemRibKind, - |this| { - // If this is a trait impl, ensure the type - // exists in trait - this.check_trait_item( - item.id, - item.ident, - &item.kind, - TypeNS, - item.span, - |i, s, c| TypeNotMemberOfTrait(i, s, c), - ); - visit::walk_assoc_item( - this, - item, - AssocCtxt::Impl, - ) - }, - ); - } - AssocItemKind::MacCall(_) => { - panic!("unexpanded macro in resolve!") - } - } - } - }); + let item_def_id = item_def_id.to_def_id(); + let res = + Res::SelfTy { trait_: trait_id, alias_to: Some((item_def_id, false)) }; + this.with_self_rib(res, |this| { + if let Some(trait_ref) = opt_trait_reference.as_ref() { + // Resolve type arguments in the trait path. + visit::walk_trait_ref(this, trait_ref); + } + // Resolve the self type. + this.visit_ty(self_type); + // Resolve the generic parameters. + this.visit_generics(generics); + + // Resolve the items within the impl. + this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, + |this| { + this.with_current_self_type(self_type, |this| { + this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| { + debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)"); + for item in impl_items { + use crate::ResolutionError::*; + match &item.kind { + AssocItemKind::Const(_default, _ty, _expr) => { + debug!("resolve_implementation AssocItemKind::Const"); + // If this is a trait impl, ensure the const + // exists in trait + this.check_trait_item( + item.id, + item.ident, + &item.kind, + ValueNS, + item.span, + |i, s, c| ConstNotMemberOfTrait(i, s, c), + ); + + // We allow arbitrary const expressions inside of associated consts, + // even if they are potentially not const evaluatable. + // + // Type parameters can already be used and as associated consts are + // not used as part of the type system, this is far less surprising. + this.with_constant_rib( + IsRepeatExpr::No, + true, + None, + |this| { + visit::walk_assoc_item( + this, + item, + AssocCtxt::Impl, + ) + }, + ); + } + AssocItemKind::Fn(box Fn { generics, .. }) => { + debug!("resolve_implementation AssocItemKind::Fn"); + // We also need a new scope for the impl item type parameters. + this.with_generic_param_rib( + &generics.params, + AssocItemRibKind, + LifetimeRibKind::Generics { span: generics.span, kind: LifetimeBinderKind::Function }, + |this| { + // If this is a trait impl, ensure the method + // exists in trait + this.check_trait_item( + item.id, + item.ident, + &item.kind, + ValueNS, + item.span, + |i, s, c| MethodNotMemberOfTrait(i, s, c), + ); + + visit::walk_assoc_item( + this, + item, + AssocCtxt::Impl, + ) + }, + ); + } + AssocItemKind::TyAlias(box TyAlias { + generics, .. + }) => { + debug!("resolve_implementation AssocItemKind::TyAlias"); + // We also need a new scope for the impl item type parameters. + this.with_generic_param_rib( + &generics.params, + AssocItemRibKind, + LifetimeRibKind::Generics { span: generics.span, kind: LifetimeBinderKind::Item }, + |this| { + // If this is a trait impl, ensure the type + // exists in trait + this.check_trait_item( + item.id, + item.ident, + &item.kind, + TypeNS, + item.span, + |i, s, c| TypeNotMemberOfTrait(i, s, c), + ); + + visit::walk_assoc_item( + this, + item, + AssocCtxt::Impl, + ) + }, + ); + } + AssocItemKind::MacCall(_) => { + panic!("unexpanded macro in resolve!") + } + } + } + }); + }); + }, + ); }); }); }); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 0926f24ae70ef..51a35f8f26db3 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1,6 +1,7 @@ use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion}; use crate::late::lifetimes::{ElisionFailureInfo, LifetimeContext}; use crate::late::{AliasPossibility, LateResolutionVisitor, RibKind}; +use crate::late::{LifetimeBinderKind, LifetimeRibKind}; use crate::path_names_to_string; use crate::{Finalize, Module, ModuleKind, ModuleOrUniformRoot}; use crate::{PathResult, PathSource, Segment}; @@ -1793,83 +1794,118 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { (*ident, within_scope) }) } -} -impl<'tcx> LifetimeContext<'_, 'tcx> { - crate fn report_missing_lifetime_specifiers( + crate fn emit_undeclared_lifetime_error( &self, - spans: Vec, - count: usize, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - struct_span_err!( - self.tcx.sess, - spans, - E0106, - "missing lifetime specifier{}", - pluralize!(count) - ) - } + lifetime_ref: &ast::Lifetime, + outer_lifetime_ref: Option, + ) { + debug_assert_ne!(lifetime_ref.ident.name, kw::UnderscoreLifetime); + let mut err = if let Some(outer) = outer_lifetime_ref { + let mut err = struct_span_err!( + self.r.session, + lifetime_ref.ident.span, + E0401, + "can't use generic parameters from outer item", + ); + err.span_label(lifetime_ref.ident.span, "use of generic parameter from outer item"); + err.span_label(outer.span, "lifetime parameter from outer item"); + err + } else { + let mut err = struct_span_err!( + self.r.session, + lifetime_ref.ident.span, + E0261, + "use of undeclared lifetime name `{}`", + lifetime_ref.ident + ); + err.span_label(lifetime_ref.ident.span, "undeclared lifetime"); + err + }; + let mut suggest_note = true; - crate fn emit_undeclared_lifetime_error(&self, lifetime_ref: &hir::Lifetime) { - let mut err = struct_span_err!( - self.tcx.sess, - lifetime_ref.span, - E0261, - "use of undeclared lifetime name `{}`", - lifetime_ref - ); - err.span_label(lifetime_ref.span, "undeclared lifetime"); - let mut suggested_spans = vec![]; - for missing in &self.missing_named_lifetime_spots { - match missing { - MissingLifetimeSpot::Generics(generics) => { - let (span, sugg) = if let Some(param) = generics.params.iter().find(|p| { - !matches!( - p.kind, - hir::GenericParamKind::Type { synthetic: true, .. } - | hir::GenericParamKind::Lifetime { - kind: hir::LifetimeParamKind::Elided, - } - ) - }) { - (param.span.shrink_to_lo(), format!("{}, ", lifetime_ref)) - } else { - (generics.span, format!("<{}>", lifetime_ref)) - }; - if suggested_spans.contains(&span) { + for rib in self.lifetime_ribs.iter().rev() { + match rib.kind { + LifetimeRibKind::Generics { span, kind } => { + if !span.can_be_used_for_suggestions() && suggest_note { + suggest_note = false; // Avoid displaying the same help multiple times. + err.span_label( + span, + &format!( + "lifetime `{}` is missing in item created through this procedural macro", + lifetime_ref.ident, + ), + ); continue; } - suggested_spans.push(span); - if span.can_be_used_for_suggestions() { + + let higher_ranked = matches!( + kind, + LifetimeBinderKind::BareFnType + | LifetimeBinderKind::PolyTrait + | LifetimeBinderKind::WhereBound + ); + let (span, sugg) = if span.is_empty() { + let sugg = format!( + "{}<{}>{}", + if higher_ranked { "for" } else { "" }, + lifetime_ref.ident, + if higher_ranked { " " } else { "" }, + ); + (span, sugg) + } else { + let span = + self.r.session.source_map().span_through_char(span, '<').shrink_to_hi(); + let sugg = format!("{}, ", lifetime_ref.ident); + (span, sugg) + }; + if higher_ranked { err.span_suggestion( span, - &format!("consider introducing lifetime `{}` here", lifetime_ref), + &format!( + "consider making the {} lifetime-generic with a new `{}` lifetime", + kind.descr(), + lifetime_ref + ), + sugg, + Applicability::MaybeIncorrect, + ); + err.note_once( + "for more information on higher-ranked polymorphism, visit \ + https://doc.rust-lang.org/nomicon/hrtb.html", + ); + } else { + err.span_suggestion( + span, + &format!("consider introducing lifetime `{}` here", lifetime_ref.ident), sugg, Applicability::MaybeIncorrect, ); } } - MissingLifetimeSpot::HigherRanked { span, span_type } => { - err.span_suggestion( - *span, - &format!( - "consider making the {} lifetime-generic with a new `{}` lifetime", - span_type.descr(), - lifetime_ref - ), - span_type.suggestion(&lifetime_ref.to_string()), - Applicability::MaybeIncorrect, - ); - err.note( - "for more information on higher-ranked polymorphism, visit \ - https://doc.rust-lang.org/nomicon/hrtb.html", - ); - } + LifetimeRibKind::Item => break, _ => {} } } + err.emit(); } +} + +impl<'tcx> LifetimeContext<'_, 'tcx> { + crate fn report_missing_lifetime_specifiers( + &self, + spans: Vec, + count: usize, + ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + struct_span_err!( + self.tcx.sess, + spans, + E0106, + "missing lifetime specifier{}", + pluralize!(count) + ) + } /// Returns whether to add `'static` lifetime to the suggested lifetime list. crate fn report_elision_failure( diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 1aa1d51e2efc8..72ca9918e122f 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -2312,7 +2312,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { self.insert_lifetime(lifetime_ref, def); } else { - self.emit_undeclared_lifetime_error(lifetime_ref); + self.tcx.sess.delay_span_bug( + lifetime_ref.span, + &format!("Could not resolve {:?} in scope {:#?}", lifetime_ref, self.scope,), + ); } } @@ -3119,18 +3122,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { if let hir::ParamName::Plain(_) = lifetime_i_name { let name = lifetime_i_name.ident().name; if name == kw::UnderscoreLifetime || name == kw::StaticLifetime { - let mut err = struct_span_err!( - self.tcx.sess, - lifetime_i.span, - E0262, - "invalid lifetime parameter name: `{}`", - lifetime_i.name.ident(), - ); - err.span_label( + self.tcx.sess.delay_span_bug( lifetime_i.span, - format!("{} is a reserved lifetime name", name), + &format!("invalid lifetime parameter name: `{}`", lifetime_i.name.ident()), ); - err.emit(); } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 0335c40d70d8c..7262d150f4c2c 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -11,6 +11,7 @@ #![feature(drain_filter)] #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] +#![feature(if_let_guard)] #![feature(let_chains)] #![feature(let_else)] #![feature(never_type)] @@ -1358,9 +1359,17 @@ impl<'a> Resolver<'a> { } pub fn next_node_id(&mut self) -> NodeId { - let next = - self.next_node_id.as_u32().checked_add(1).expect("input too large; ran out of NodeIds"); - mem::replace(&mut self.next_node_id, ast::NodeId::from_u32(next)) + let start = self.next_node_id; + let next = start.as_u32().checked_add(1).expect("input too large; ran out of NodeIds"); + self.next_node_id = ast::NodeId::from_u32(next); + start + } + + pub fn next_node_ids(&mut self, count: usize) -> std::ops::Range { + let start = self.next_node_id; + let end = start.as_usize().checked_add(count).expect("input too large; ran out of NodeIds"); + self.next_node_id = ast::NodeId::from_usize(end); + start..self.next_node_id } pub fn lint_buffer(&mut self) -> &mut LintBuffer { From ca57bada05373ff227c661cc542e99c92b70c0ee Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 6 Mar 2022 15:44:48 +0100 Subject: [PATCH 5/8] Bless tests. --- ...t-in-trait-path-undeclared-lifetime.stderr | 14 +- ...ssociated_type_undeclared_lifetimes.stderr | 19 +- .../generic-associated-types/issue-67510.rs | 8 +- .../issue-67510.stderr | 53 +++- .../generic-associated-types/issue-70304.rs | 13 +- .../issue-70304.stderr | 2 +- .../generics/generic-extern-lifetime.stderr | 21 +- .../trait-elided.rs | 7 +- .../trait-elided.stderr | 2 +- src/test/ui/issues/issue-10412.rs | 18 +- src/test/ui/issues/issue-10412.stderr | 28 +-- ...ime-used-in-debug-macro-issue-70152.stderr | 10 +- .../method-call-lifetime-args-unresolved.rs | 5 +- ...ethod-call-lifetime-args-unresolved.stderr | 17 +- src/test/ui/regions/regions-name-static.rs | 5 +- .../ui/regions/regions-name-undeclared.rs | 8 +- .../ui/regions/regions-name-undeclared.stderr | 104 ++++---- .../fn-missing-lifetime-in-item.stderr | 8 +- .../missing-lifetimes-in-signature.rs | 31 ++- .../missing-lifetimes-in-signature.stderr | 229 +++++++++++++++++- ...ssue-69136-inner-lifetime-resolve-error.rs | 2 + ...-69136-inner-lifetime-resolve-error.stderr | 40 ++- src/test/ui/underscore-lifetime/in-binder.rs | 8 +- .../where-lifetime-resolution.stderr | 33 ++- 24 files changed, 527 insertions(+), 158 deletions(-) diff --git a/src/test/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr b/src/test/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr index 317897ae70f72..1792d8db292c4 100644 --- a/src/test/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr +++ b/src/test/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr @@ -2,9 +2,17 @@ error[E0261]: use of undeclared lifetime name `'x` --> $DIR/gat-in-trait-path-undeclared-lifetime.rs:8:35 | LL | fn _f(arg : Box X = &'a [u32]>>) {} - | - ^^ undeclared lifetime - | | - | help: consider introducing lifetime `'x` here: `<'x>` + | ^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'x` lifetime + | +LL | fn _f(arg : Box X = &'a [u32]>>) {} + | +++ +help: consider introducing lifetime `'x` here + | +LL | fn _f<'x>(arg : Box X = &'a [u32]>>) {} + | ++++ error[E0582]: binding for associated type `Y` references lifetime `'a`, which does not appear in the trait input types --> $DIR/gat-in-trait-path-undeclared-lifetime.rs:8:33 diff --git a/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr b/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr index bf0ca8715036b..a4bb361900fe1 100644 --- a/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr +++ b/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr @@ -4,14 +4,19 @@ error[E0261]: use of undeclared lifetime name `'b` LL | + Deref>; | ^^ undeclared lifetime | -help: consider introducing lifetime `'b` here + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'b` lifetime | -LL | trait Iterable<'b> { - | ++++ +LL | + for<'b> Deref>; + | +++++++ help: consider introducing lifetime `'b` here | LL | type Iter<'b, 'a>: Iterator> | +++ +help: consider introducing lifetime `'b` here + | +LL | trait Iterable<'b> { + | ++++ error[E0261]: use of undeclared lifetime name `'undeclared` --> $DIR/generic_associated_type_undeclared_lifetimes.rs:11:41 @@ -21,12 +26,12 @@ LL | fn iter<'a>(&'a self) -> Self::Iter<'undeclared>; | help: consider introducing lifetime `'undeclared` here | -LL | trait Iterable<'undeclared> { - | +++++++++++++ -help: consider introducing lifetime `'undeclared` here - | LL | fn iter<'undeclared, 'a>(&'a self) -> Self::Iter<'undeclared>; | ++++++++++++ +help: consider introducing lifetime `'undeclared` here + | +LL | trait Iterable<'undeclared> { + | +++++++++++++ error: aborting due to 2 previous errors diff --git a/src/test/ui/generic-associated-types/issue-67510.rs b/src/test/ui/generic-associated-types/issue-67510.rs index e81a5b231a001..5725b660ab234 100644 --- a/src/test/ui/generic-associated-types/issue-67510.rs +++ b/src/test/ui/generic-associated-types/issue-67510.rs @@ -4,9 +4,9 @@ trait X { type Y<'a>; } -fn f(x: Box=&'a ()>>) {} - //~^ ERROR: use of undeclared lifetime name `'a` - //~| ERROR: use of undeclared lifetime name `'a` - +fn f(x: Box = &'a ()>>) {} +//~^ ERROR: use of undeclared lifetime name `'a` +//~| ERROR: use of undeclared lifetime name `'a` +//~| ERROR: the trait `X` cannot be made into an object [E0038] fn main() {} diff --git a/src/test/ui/generic-associated-types/issue-67510.stderr b/src/test/ui/generic-associated-types/issue-67510.stderr index abc02b33e0e6a..8aeda22bad75f 100644 --- a/src/test/ui/generic-associated-types/issue-67510.stderr +++ b/src/test/ui/generic-associated-types/issue-67510.stderr @@ -1,19 +1,50 @@ error[E0261]: use of undeclared lifetime name `'a` --> $DIR/issue-67510.rs:7:21 | -LL | fn f(x: Box=&'a ()>>) {} - | - ^^ undeclared lifetime - | | - | help: consider introducing lifetime `'a` here: `<'a>` +LL | fn f(x: Box = &'a ()>>) {} + | ^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'a` lifetime + | +LL | fn f(x: Box X = &'a ()>>) {} + | +++++++ +help: consider introducing lifetime `'a` here + | +LL | fn f<'a>(x: Box = &'a ()>>) {} + | ++++ error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/issue-67510.rs:7:26 + --> $DIR/issue-67510.rs:7:28 + | +LL | fn f(x: Box = &'a ()>>) {} + | ^^ undeclared lifetime + | +help: consider making the bound lifetime-generic with a new `'a` lifetime + | +LL | fn f(x: Box X = &'a ()>>) {} + | +++++++ +help: consider introducing lifetime `'a` here + | +LL | fn f<'a>(x: Box = &'a ()>>) {} + | ++++ + +error[E0038]: the trait `X` cannot be made into an object + --> $DIR/issue-67510.rs:7:13 + | +LL | fn f(x: Box = &'a ()>>) {} + | ^^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/issue-67510.rs:4:10 | -LL | fn f(x: Box=&'a ()>>) {} - | - ^^ undeclared lifetime - | | - | help: consider introducing lifetime `'a` here: `<'a>` +LL | trait X { + | - this trait cannot be made into an object... +LL | type Y<'a>; + | ^ ...because it contains the generic associated type `Y` + = help: consider moving `Y` to another trait -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0261`. +Some errors have detailed explanations: E0038, E0261. +For more information about an error, try `rustc --explain E0038`. diff --git a/src/test/ui/generic-associated-types/issue-70304.rs b/src/test/ui/generic-associated-types/issue-70304.rs index ae64f9310d112..448d7ec287395 100644 --- a/src/test/ui/generic-associated-types/issue-70304.rs +++ b/src/test/ui/generic-associated-types/issue-70304.rs @@ -12,13 +12,10 @@ impl Document for DocumentImpl { type Cursor<'a> = DocCursorImpl<'a>; fn cursor(&self) -> Self::Cursor<'_> { - DocCursorImpl { - document: &self, - } + DocCursorImpl { document: &self } } } - trait DocCursor<'a> {} struct DocCursorImpl<'a> { @@ -35,7 +32,6 @@ where _phantom: std::marker::PhantomData<&'d ()>, } - impl<'d, Cursor> Lexer<'d, Cursor> where Cursor: DocCursor<'d>, @@ -44,15 +40,12 @@ where where Doc: Document = Cursor>, { - Lexer { - cursor: document.cursor(), - _phantom: std::marker::PhantomData, - } + Lexer { cursor: document.cursor(), _phantom: std::marker::PhantomData } } } fn create_doc() -> impl Document = DocCursorImpl<'_>> { - //~^ ERROR: missing lifetime specifier + //~^ ERROR: missing lifetime specifier DocumentImpl {} } diff --git a/src/test/ui/generic-associated-types/issue-70304.stderr b/src/test/ui/generic-associated-types/issue-70304.stderr index c53dbf63a3c5b..c5f59a24057d2 100644 --- a/src/test/ui/generic-associated-types/issue-70304.stderr +++ b/src/test/ui/generic-associated-types/issue-70304.stderr @@ -1,5 +1,5 @@ error[E0106]: missing lifetime specifier - --> $DIR/issue-70304.rs:54:41 + --> $DIR/issue-70304.rs:47:41 | LL | fn create_doc() -> impl Document = DocCursorImpl<'_>> { | ^^ expected named lifetime parameter diff --git a/src/test/ui/generics/generic-extern-lifetime.stderr b/src/test/ui/generics/generic-extern-lifetime.stderr index 909848604ec8a..33332e760f582 100644 --- a/src/test/ui/generics/generic-extern-lifetime.stderr +++ b/src/test/ui/generics/generic-extern-lifetime.stderr @@ -2,7 +2,9 @@ error[E0261]: use of undeclared lifetime name `'a` --> $DIR/generic-extern-lifetime.rs:6:26 | LL | pub fn life2<'b>(x: &'a i32, y: &'b i32); - | ^^ undeclared lifetime + | - ^^ undeclared lifetime + | | + | help: consider introducing lifetime `'a` here: `'a,` error[E0261]: use of undeclared lifetime name `'a` --> $DIR/generic-extern-lifetime.rs:8:37 @@ -13,8 +15,12 @@ LL | pub fn life4<'b>(x: for<'c> fn(&'a i32)); = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html help: consider making the type lifetime-generic with a new `'a` lifetime | -LL | pub fn life4<'b>(x: for<'c, 'a> fn(&'a i32)); - | ++++ +LL | pub fn life4<'b>(x: for<'a, 'c> fn(&'a i32)); + | +++ +help: consider introducing lifetime `'a` here + | +LL | pub fn life4<'a, 'b>(x: for<'c> fn(&'a i32)); + | +++ error[E0261]: use of undeclared lifetime name `'a` --> $DIR/generic-extern-lifetime.rs:11:39 @@ -22,11 +28,14 @@ error[E0261]: use of undeclared lifetime name `'a` LL | pub fn life7<'b>() -> for<'c> fn(&'a i32); | ^^ undeclared lifetime | - = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html help: consider making the type lifetime-generic with a new `'a` lifetime | -LL | pub fn life7<'b>() -> for<'c, 'a> fn(&'a i32); - | ++++ +LL | pub fn life7<'b>() -> for<'a, 'c> fn(&'a i32); + | +++ +help: consider introducing lifetime `'a` here + | +LL | pub fn life7<'a, 'b>() -> for<'c> fn(&'a i32); + | +++ error: aborting due to 3 previous errors diff --git a/src/test/ui/impl-header-lifetime-elision/trait-elided.rs b/src/test/ui/impl-header-lifetime-elision/trait-elided.rs index 102d259b0c87a..c3e76d9cb5a03 100644 --- a/src/test/ui/impl-header-lifetime-elision/trait-elided.rs +++ b/src/test/ui/impl-header-lifetime-elision/trait-elided.rs @@ -1,9 +1,8 @@ #![allow(warnings)] -trait MyTrait<'a> { } +trait MyTrait<'a> {} -impl MyTrait for u32 { - //~^ ERROR implicit elided lifetime not allowed here -} +impl MyTrait for u32 {} +//~^ ERROR implicit elided lifetime not allowed here fn main() {} diff --git a/src/test/ui/impl-header-lifetime-elision/trait-elided.stderr b/src/test/ui/impl-header-lifetime-elision/trait-elided.stderr index 15bc3f106b9c4..be918d0a30ce8 100644 --- a/src/test/ui/impl-header-lifetime-elision/trait-elided.stderr +++ b/src/test/ui/impl-header-lifetime-elision/trait-elided.stderr @@ -1,7 +1,7 @@ error[E0726]: implicit elided lifetime not allowed here --> $DIR/trait-elided.rs:5:6 | -LL | impl MyTrait for u32 { +LL | impl MyTrait for u32 {} | ^^^^^^^- help: indicate the anonymous lifetime: `<'_>` | = note: assuming a `'static` lifetime... diff --git a/src/test/ui/issues/issue-10412.rs b/src/test/ui/issues/issue-10412.rs index 020585136856b..0de170161b514 100644 --- a/src/test/ui/issues/issue-10412.rs +++ b/src/test/ui/issues/issue-10412.rs @@ -1,16 +1,20 @@ -trait Serializable<'self, T> { //~ ERROR lifetimes cannot use keyword names - fn serialize(val : &'self T) -> Vec; //~ ERROR lifetimes cannot use keyword names - fn deserialize(repr : &[u8]) -> &'self T; //~ ERROR lifetimes cannot use keyword names +trait Serializable<'self, T> { + //~^ ERROR lifetimes cannot use keyword names + fn serialize(val: &'self T) -> Vec; //~ ERROR lifetimes cannot use keyword names + fn deserialize(repr: &[u8]) -> &'self T; //~ ERROR lifetimes cannot use keyword names } -impl<'self> Serializable for &'self str { //~ ERROR lifetimes cannot use keyword names +impl<'self> Serializable for &'self str { //~^ ERROR lifetimes cannot use keyword names + //~| ERROR lifetimes cannot use keyword names //~| ERROR implicit elided lifetime not allowed here - //~| ERROR the size for values of type `str` cannot be known at compilation time - fn serialize(val : &'self str) -> Vec { //~ ERROR lifetimes cannot use keyword names + //~| ERROR the size for values of type `str` cannot be known at compilation time [E0277] + fn serialize(val: &'self str) -> Vec { + //~^ ERROR lifetimes cannot use keyword names vec![1] } - fn deserialize(repr: &[u8]) -> &'self str { //~ ERROR lifetimes cannot use keyword names + fn deserialize(repr: &[u8]) -> &'self str { + //~^ ERROR lifetimes cannot use keyword names "hi" } } diff --git a/src/test/ui/issues/issue-10412.stderr b/src/test/ui/issues/issue-10412.stderr index a91b3c90ebb25..a65005fd72d09 100644 --- a/src/test/ui/issues/issue-10412.stderr +++ b/src/test/ui/issues/issue-10412.stderr @@ -5,43 +5,43 @@ LL | trait Serializable<'self, T> { | ^^^^^ error: lifetimes cannot use keyword names - --> $DIR/issue-10412.rs:2:25 + --> $DIR/issue-10412.rs:3:24 | -LL | fn serialize(val : &'self T) -> Vec; - | ^^^^^ +LL | fn serialize(val: &'self T) -> Vec; + | ^^^^^ error: lifetimes cannot use keyword names - --> $DIR/issue-10412.rs:3:38 + --> $DIR/issue-10412.rs:4:37 | -LL | fn deserialize(repr : &[u8]) -> &'self T; - | ^^^^^ +LL | fn deserialize(repr: &[u8]) -> &'self T; + | ^^^^^ error: lifetimes cannot use keyword names - --> $DIR/issue-10412.rs:6:6 + --> $DIR/issue-10412.rs:7:6 | LL | impl<'self> Serializable for &'self str { | ^^^^^ error: lifetimes cannot use keyword names - --> $DIR/issue-10412.rs:6:36 + --> $DIR/issue-10412.rs:7:36 | LL | impl<'self> Serializable for &'self str { | ^^^^^ error: lifetimes cannot use keyword names - --> $DIR/issue-10412.rs:10:25 + --> $DIR/issue-10412.rs:12:24 | -LL | fn serialize(val : &'self str) -> Vec { - | ^^^^^ +LL | fn serialize(val: &'self str) -> Vec { + | ^^^^^ error: lifetimes cannot use keyword names - --> $DIR/issue-10412.rs:13:37 + --> $DIR/issue-10412.rs:16:37 | LL | fn deserialize(repr: &[u8]) -> &'self str { | ^^^^^ error[E0726]: implicit elided lifetime not allowed here - --> $DIR/issue-10412.rs:6:13 + --> $DIR/issue-10412.rs:7:13 | LL | impl<'self> Serializable for &'self str { | ^^^^^^^^^^^^^^^^^ help: indicate the anonymous lifetime: `Serializable<'_, str>` @@ -49,7 +49,7 @@ LL | impl<'self> Serializable for &'self str { = note: assuming a `'static` lifetime... error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/issue-10412.rs:6:13 + --> $DIR/issue-10412.rs:7:13 | LL | impl<'self> Serializable for &'self str { | ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time diff --git a/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr b/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr index cb459f31cd243..0d6ade41511fd 100644 --- a/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr +++ b/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr @@ -9,6 +9,8 @@ LL | a: &'b str, error[E0261]: use of undeclared lifetime name `'b` --> $DIR/undeclared-lifetime-used-in-debug-macro-issue-70152.rs:3:9 | +LL | #[derive(Eq, PartialEq)] + | -- lifetime `'b` is missing in item created through this procedural macro LL | struct Test { | - help: consider introducing lifetime `'b` here: `<'b>` LL | a: &'b str, @@ -22,12 +24,12 @@ LL | fn foo(&'b self) {} | help: consider introducing lifetime `'b` here | -LL | impl<'b> T for Test { - | ++++ -help: consider introducing lifetime `'b` here - | LL | fn foo<'b>(&'b self) {} | ++++ +help: consider introducing lifetime `'b` here + | +LL | impl<'b> T for Test { + | ++++ error: aborting due to 3 previous errors diff --git a/src/test/ui/methods/method-call-lifetime-args-unresolved.rs b/src/test/ui/methods/method-call-lifetime-args-unresolved.rs index d16ba3df47b63..ba7231070a0f4 100644 --- a/src/test/ui/methods/method-call-lifetime-args-unresolved.rs +++ b/src/test/ui/methods/method-call-lifetime-args-unresolved.rs @@ -1,3 +1,6 @@ fn main() { - 0.clone::<'a>(); //~ ERROR use of undeclared lifetime name `'a` + 0.clone::<'a>(); + //~^ ERROR use of undeclared lifetime name `'a` + //~| WARN cannot specify lifetime arguments explicitly if late bound + //~| WARN this was previously accepted by the compiler } diff --git a/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr b/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr index c9f235c4f7df7..78af19586a1b7 100644 --- a/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr +++ b/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr @@ -6,6 +6,21 @@ LL | fn main() { LL | 0.clone::<'a>(); | ^^ undeclared lifetime -error: aborting due to previous error +warning: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-unresolved.rs:2:15 + | +LL | 0.clone::<'a>(); + | ^^ + | + ::: $SRC_DIR/core/src/clone.rs:LL:COL + | +LL | fn clone(&self) -> Self; + | - the late bound lifetime parameter is introduced here + | + = note: `#[warn(late_bound_lifetime_arguments)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #42868 + +error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0261`. diff --git a/src/test/ui/regions/regions-name-static.rs b/src/test/ui/regions/regions-name-static.rs index 730fd99aa68c2..da316c6ef5e43 100644 --- a/src/test/ui/regions/regions-name-static.rs +++ b/src/test/ui/regions/regions-name-static.rs @@ -1,5 +1,6 @@ -struct Foo<'static> { //~ ERROR invalid lifetime parameter name: `'static` - x: &'static isize +struct Foo<'static> { + //~^ ERROR invalid lifetime parameter name: `'static` + x: &'static isize, } fn main() {} diff --git a/src/test/ui/regions/regions-name-undeclared.rs b/src/test/ui/regions/regions-name-undeclared.rs index b8f50a40c4523..7b6ede19341b4 100644 --- a/src/test/ui/regions/regions-name-undeclared.rs +++ b/src/test/ui/regions/regions-name-undeclared.rs @@ -23,14 +23,14 @@ fn bar<'a>(x: &'a isize) { let y: &'a isize = x; // &'a is not visible to *items*: - type X = Option<&'a isize>; //~ ERROR undeclared lifetime + type X = Option<&'a isize>; //~ ERROR can't use generic parameters from outer item enum E { - E1(&'a isize) //~ ERROR undeclared lifetime + E1(&'a isize) //~ ERROR can't use generic parameters from outer item } struct S { - f: &'a isize //~ ERROR undeclared lifetime + f: &'a isize //~ ERROR can't use generic parameters from outer item } - fn f(a: &'a isize) { } //~ ERROR undeclared lifetime + fn f(a: &'a isize) { } //~ ERROR can't use generic parameters from outer item // &'a CAN be declared on functions and used then: fn g<'a>(a: &'a isize) { } // OK diff --git a/src/test/ui/regions/regions-name-undeclared.stderr b/src/test/ui/regions/regions-name-undeclared.stderr index 4399263f716ed..532603de5f783 100644 --- a/src/test/ui/regions/regions-name-undeclared.stderr +++ b/src/test/ui/regions/regions-name-undeclared.stderr @@ -1,19 +1,3 @@ -error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/regions-name-undeclared.rs:28:13 - | -LL | enum E { - | - help: consider introducing lifetime `'a` here: `<'a>` -LL | E1(&'a isize) - | ^^ undeclared lifetime - -error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/regions-name-undeclared.rs:31:13 - | -LL | struct S { - | - help: consider introducing lifetime `'a` here: `<'a>` -LL | f: &'a isize - | ^^ undeclared lifetime - error[E0261]: use of undeclared lifetime name `'b` --> $DIR/regions-name-undeclared.rs:16:24 | @@ -22,12 +6,12 @@ LL | fn m4(&self, arg: &'b isize) { } | help: consider introducing lifetime `'b` here | -LL | impl<'b, 'a> Foo<'a> { - | +++ -help: consider introducing lifetime `'b` here - | LL | fn m4<'b>(&self, arg: &'b isize) { } | ++++ +help: consider introducing lifetime `'b` here + | +LL | impl<'b, 'a> Foo<'a> { + | +++ error[E0261]: use of undeclared lifetime name `'b` --> $DIR/regions-name-undeclared.rs:17:12 @@ -37,12 +21,12 @@ LL | fn m5(&'b self) { } | help: consider introducing lifetime `'b` here | -LL | impl<'b, 'a> Foo<'a> { - | +++ -help: consider introducing lifetime `'b` here - | LL | fn m5<'b>(&'b self) { } | ++++ +help: consider introducing lifetime `'b` here + | +LL | impl<'b, 'a> Foo<'a> { + | +++ error[E0261]: use of undeclared lifetime name `'b` --> $DIR/regions-name-undeclared.rs:18:27 @@ -52,26 +36,54 @@ LL | fn m6(&self, arg: Foo<'b>) { } | help: consider introducing lifetime `'b` here | -LL | impl<'b, 'a> Foo<'a> { - | +++ -help: consider introducing lifetime `'b` here - | LL | fn m6<'b>(&self, arg: Foo<'b>) { } | ++++ +help: consider introducing lifetime `'b` here + | +LL | impl<'b, 'a> Foo<'a> { + | +++ -error[E0261]: use of undeclared lifetime name `'a` +error[E0401]: can't use generic parameters from outer item --> $DIR/regions-name-undeclared.rs:26:22 | +LL | fn bar<'a>(x: &'a isize) { + | -- lifetime parameter from outer item +... LL | type X = Option<&'a isize>; - | - ^^ undeclared lifetime + | - ^^ use of generic parameter from outer item | | | help: consider introducing lifetime `'a` here: `<'a>` -error[E0261]: use of undeclared lifetime name `'a` +error[E0401]: can't use generic parameters from outer item + --> $DIR/regions-name-undeclared.rs:28:13 + | +LL | fn bar<'a>(x: &'a isize) { + | -- lifetime parameter from outer item +... +LL | enum E { + | - help: consider introducing lifetime `'a` here: `<'a>` +LL | E1(&'a isize) + | ^^ use of generic parameter from outer item + +error[E0401]: can't use generic parameters from outer item + --> $DIR/regions-name-undeclared.rs:31:13 + | +LL | fn bar<'a>(x: &'a isize) { + | -- lifetime parameter from outer item +... +LL | struct S { + | - help: consider introducing lifetime `'a` here: `<'a>` +LL | f: &'a isize + | ^^ use of generic parameter from outer item + +error[E0401]: can't use generic parameters from outer item --> $DIR/regions-name-undeclared.rs:33:14 | +LL | fn bar<'a>(x: &'a isize) { + | -- lifetime parameter from outer item +... LL | fn f(a: &'a isize) { } - | - ^^ undeclared lifetime + | - ^^ use of generic parameter from outer item | | | help: consider introducing lifetime `'a` here: `<'a>` @@ -90,14 +102,14 @@ LL | ... &'b isize, | ^^ undeclared lifetime | = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'b` lifetime + | +LL | b: Box FnOnce(&'a isize, + | +++ help: consider introducing lifetime `'b` here | LL | fn fn_types<'b>(a: &'a isize, | ++++ -help: consider making the bound lifetime-generic with a new `'b` lifetime - | -LL | b: Box FnOnce(&'a isize, - | ++++ error[E0261]: use of undeclared lifetime name `'b` --> $DIR/regions-name-undeclared.rs:46:36 @@ -105,15 +117,14 @@ error[E0261]: use of undeclared lifetime name `'b` LL | ... &'b isize)>, | ^^ undeclared lifetime | - = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'b` lifetime + | +LL | b: Box FnOnce(&'a isize, + | +++ help: consider introducing lifetime `'b` here | LL | fn fn_types<'b>(a: &'a isize, | ++++ -help: consider making the bound lifetime-generic with a new `'b` lifetime - | -LL | b: Box FnOnce(&'a isize, - | ++++ error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-name-undeclared.rs:47:17 @@ -132,13 +143,14 @@ LL | async fn buggy(&self) -> &'a str { | help: consider introducing lifetime `'a` here | -LL | impl<'a> Bug { - | ++++ -help: consider introducing lifetime `'a` here - | LL | async fn buggy<'a>(&self) -> &'a str { | ++++ +help: consider introducing lifetime `'a` here + | +LL | impl<'a> Bug { + | ++++ error: aborting due to 12 previous errors -For more information about this error, try `rustc --explain E0261`. +Some errors have detailed explanations: E0261, E0401. +For more information about an error, try `rustc --explain E0261`. diff --git a/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr b/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr index 7c0f8d199a965..a761ec5916745 100644 --- a/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr +++ b/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr @@ -5,14 +5,14 @@ LL | struct S1 &'a i32>(F); | ^^ undeclared lifetime | = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html -help: consider introducing lifetime `'a` here - | -LL | struct S1<'a, F: Fn(&i32, &i32) -> &'a i32>(F); - | +++ help: consider making the bound lifetime-generic with a new `'a` lifetime | LL | struct S1 Fn(&i32, &i32) -> &'a i32>(F); | +++++++ +help: consider introducing lifetime `'a` here + | +LL | struct S1<'a, F: Fn(&i32, &i32) -> &'a i32>(F); + | +++ error[E0106]: missing lifetime specifier --> $DIR/fn-missing-lifetime-in-item.rs:2:32 diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs index dd434ea531878..647b343fe0694 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs @@ -14,28 +14,31 @@ impl Get for Foo { fn foo(g: G, dest: &mut T) -> impl FnOnce() where - G: Get + G: Get, { move || { + //~^ ERROR hidden type for `impl Trait` captures lifetime *dest = g.get(); } } // After applying suggestion for `foo`: fn bar(g: G, dest: &mut T) -> impl FnOnce() + '_ +//~^ ERROR the parameter type `G` may not live long enough where - G: Get + G: Get, { + //~^ ERROR the parameter type `G` may not live long enough move || { *dest = g.get(); } } - // After applying suggestion for `bar`: -fn baz(g: G, dest: &mut T) -> impl FnOnce() + '_ //~ ERROR undeclared lifetime +fn baz(g: G, dest: &mut T) -> impl FnOnce() + '_ +//~^ ERROR undeclared lifetime name `'a` where - G: Get + G: Get, { move || { *dest = g.get(); @@ -44,9 +47,11 @@ where // After applying suggestion for `baz`: fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ +//~^ ERROR the parameter type `G` may not live long enough where - G: Get + G: Get, { + //~^ ERROR the parameter type `G` may not live long enough move || { *dest = g.get(); } @@ -55,6 +60,8 @@ where // Same as above, but show that we pay attention to lifetime names from parent item impl<'a> Foo { fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { + //~^ ERROR the parameter type `G` may not live long enough + //~| ERROR the parameter type `G` may not live long enough move || { *dest = g.get(); } @@ -63,8 +70,9 @@ impl<'a> Foo { // After applying suggestion for `qux`: fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a +//~^ ERROR explicit lifetime required in the type of `dest` where - G: Get + G: Get, { move || { *dest = g.get(); @@ -73,19 +81,20 @@ where // Potential incorrect attempt: fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a +//~^ ERROR the parameter type `G` may not live long enough where - G: Get + G: Get, { + //~^ ERROR the parameter type `G` may not live long enough move || { *dest = g.get(); } } - // We need to tie the lifetime of `G` with the lifetime of `&mut T` and the returned closure: fn ok<'a, G: 'a, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a where - G: Get + G: Get, { move || { *dest = g.get(); @@ -95,7 +104,7 @@ 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 where - G: Get + G: Get, { move || { *dest = g.get(); diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index 916a6c2bf12af..6d538dfd609a8 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -1,11 +1,234 @@ error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/missing-lifetimes-in-signature.rs:36:11 + --> $DIR/missing-lifetimes-in-signature.rs:38:11 | LL | fn baz(g: G, dest: &mut T) -> impl FnOnce() + '_ | - ^^ undeclared lifetime | | | help: consider introducing lifetime `'a` here: `'a,` -error: aborting due to previous error +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds + --> $DIR/missing-lifetimes-in-signature.rs:19:5 + | +LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() + | ------ hidden type `[closure@$DIR/missing-lifetimes-in-signature.rs:19:5: 22:6]` captures the anonymous lifetime defined here +... +LL | / move || { +LL | | +LL | | *dest = g.get(); +LL | | } + | |_____^ + | +help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound + | +LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() + '_ + | ++++ + +error[E0311]: the parameter type `G` may not live long enough + --> $DIR/missing-lifetimes-in-signature.rs:26:37 + | +LL | fn bar(g: G, dest: &mut T) -> impl FnOnce() + '_ + | ^^^^^^^^^^^^^^^^^^ + | +note: the parameter type `G` must be valid for the anonymous lifetime defined here... + --> $DIR/missing-lifetimes-in-signature.rs:26:26 + | +LL | fn bar(g: G, dest: &mut T) -> impl FnOnce() + '_ + | ^^^^^^ +note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:32:5: 34:6]` will meet its required lifetime bounds + --> $DIR/missing-lifetimes-in-signature.rs:26:37 + | +LL | fn bar(g: G, dest: &mut T) -> impl FnOnce() + '_ + | ^^^^^^^^^^^^^^^^^^ +help: consider introducing an explicit lifetime bound + | +LL | fn bar<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a + | ~~~~~ ++++ + +error[E0311]: the parameter type `G` may not live long enough + --> $DIR/missing-lifetimes-in-signature.rs:30:1 + | +LL | / { +LL | | +LL | | move || { +LL | | *dest = g.get(); +LL | | } +LL | | } + | |_^ + | +note: the parameter type `G` must be valid for the anonymous lifetime defined here... + --> $DIR/missing-lifetimes-in-signature.rs:26:26 + | +LL | fn bar(g: G, dest: &mut T) -> impl FnOnce() + '_ + | ^^^^^^ +note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:32:5: 34:6]` will meet its required lifetime bounds + --> $DIR/missing-lifetimes-in-signature.rs:30:1 + | +LL | / { +LL | | +LL | | move || { +LL | | *dest = g.get(); +LL | | } +LL | | } + | |_^ +help: consider introducing an explicit lifetime bound + | +LL ~ fn bar<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ +LL | +LL | where +LL | G: Get, +LL | { +LL | + ... + +error[E0311]: the parameter type `G` may not live long enough + --> $DIR/missing-lifetimes-in-signature.rs:49:45 + | +LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + | ^^^^^^^^^^^^^^^^^^ + | +note: the parameter type `G` must be valid for the anonymous lifetime defined here... + --> $DIR/missing-lifetimes-in-signature.rs:49:34 + | +LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + | ^^^^^^ +note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:55:5: 57:6]` will meet its required lifetime bounds + --> $DIR/missing-lifetimes-in-signature.rs:49:45 + | +LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + | ^^^^^^^^^^^^^^^^^^ +help: consider introducing an explicit lifetime bound + | +LL | fn qux<'b, 'a, G: 'b + 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'b + | +++ ~~~~~~~ ++++ + +error[E0311]: the parameter type `G` may not live long enough + --> $DIR/missing-lifetimes-in-signature.rs:53:1 + | +LL | / { +LL | | +LL | | move || { +LL | | *dest = g.get(); +LL | | } +LL | | } + | |_^ + | +note: the parameter type `G` must be valid for the anonymous lifetime defined here... + --> $DIR/missing-lifetimes-in-signature.rs:49:34 + | +LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + | ^^^^^^ +note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:55:5: 57:6]` will meet its required lifetime bounds + --> $DIR/missing-lifetimes-in-signature.rs:53:1 + | +LL | / { +LL | | +LL | | move || { +LL | | *dest = g.get(); +LL | | } +LL | | } + | |_^ +help: consider introducing an explicit lifetime bound + | +LL ~ fn qux<'b, 'a, G: 'b + 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ +LL | +LL | where +LL | G: Get, +LL | { +LL | + ... + +error[E0311]: the parameter type `G` may not live long enough + --> $DIR/missing-lifetimes-in-signature.rs:62:58 + | +LL | fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { + | ^^^^^^^^^^^^^^^^^^ + | +note: the parameter type `G` must be valid for the anonymous lifetime defined here... + --> $DIR/missing-lifetimes-in-signature.rs:62:47 + | +LL | fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { + | ^^^^^^ +note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:65:9: 67:10]` will meet its required lifetime bounds + --> $DIR/missing-lifetimes-in-signature.rs:62:58 + | +LL | fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { + | ^^^^^^^^^^^^^^^^^^ +help: consider introducing an explicit lifetime bound + | +LL | fn qux<'c, 'b, G: 'c + Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'c { + | +++ ~~~~~~~ ++++ + +error[E0311]: the parameter type `G` may not live long enough + --> $DIR/missing-lifetimes-in-signature.rs:62:77 + | +LL | fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { + | _____________________________________________________________________________^ +LL | | +LL | | +LL | | move || { +LL | | *dest = g.get(); +LL | | } +LL | | } + | |_____^ + | +note: the parameter type `G` must be valid for the anonymous lifetime defined here... + --> $DIR/missing-lifetimes-in-signature.rs:62:47 + | +LL | fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { + | ^^^^^^ +note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:65:9: 67:10]` will meet its required lifetime bounds + --> $DIR/missing-lifetimes-in-signature.rs:62:77 + | +LL | fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { + | _____________________________________________________________________________^ +LL | | +LL | | +LL | | move || { +LL | | *dest = g.get(); +LL | | } +LL | | } + | |_____^ +help: consider introducing an explicit lifetime bound + | +LL ~ fn qux<'c, 'b, G: 'c + Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { +LL | +LL | +LL | move || { +LL | *dest = g.get(); +LL | } + ... + +error[E0621]: explicit lifetime required in the type of `dest` + --> $DIR/missing-lifetimes-in-signature.rs:72:45 + | +LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a + | ------ ^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required + | | + | help: add explicit lifetime `'a` to the type of `dest`: `&'a mut T` + +error[E0309]: the parameter type `G` may not live long enough + --> $DIR/missing-lifetimes-in-signature.rs:83:44 + | +LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a + | - ^^^^^^^^^^^^^^^^^^ ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:89:5: 91:6]` will meet its required lifetime bounds + | | + | help: consider adding an explicit lifetime bound...: `G: 'a` + +error[E0309]: the parameter type `G` may not live long enough + --> $DIR/missing-lifetimes-in-signature.rs:87:1 + | +LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a + | - help: consider adding an explicit lifetime bound...: `G: 'a` +... +LL | / { +LL | | +LL | | move || { +LL | | *dest = g.get(); +LL | | } +LL | | } + | |_^ ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:89:5: 91:6]` will meet its required lifetime bounds + +error: aborting due to 11 previous errors -For more information about this error, try `rustc --explain E0261`. +Some errors have detailed explanations: E0261, E0309, E0621, E0700. +For more information about an error, try `rustc --explain E0261`. diff --git a/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs b/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs index 6732902c09a50..b0de8bf6aa4f2 100644 --- a/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs +++ b/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs @@ -18,5 +18,7 @@ type Return = impl WithAssoc; //~^ ERROR use of undeclared lifetime name `'a` fn my_fun() -> Return<()> {} +//~^ ERROR non-defining opaque type use in defining scope +//~| ERROR non-defining opaque type use in defining scope fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr b/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr index fe45e39d938f0..d038fbbe1b40a 100644 --- a/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr @@ -2,10 +2,42 @@ error[E0261]: use of undeclared lifetime name `'a` --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:17:65 | LL | type Return = impl WithAssoc; - | - ^^ undeclared lifetime - | | - | help: consider introducing lifetime `'a` here: `'a,` + | ^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'a` lifetime + | +LL | type Return = impl for<'a> WithAssoc; + | +++++++ +help: consider introducing lifetime `'a` here + | +LL | type Return<'a, A> = impl WithAssoc; + | +++ + +error: non-defining opaque type use in defining scope + --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:20:27 + | +LL | fn my_fun() -> Return<()> {} + | ^^ + | +note: used non-generic type `()` for generic parameter + --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:17:13 + | +LL | type Return = impl WithAssoc; + | ^ + +error: non-defining opaque type use in defining scope + --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:20:27 + | +LL | fn my_fun() -> Return<()> {} + | ^^ + | +note: used non-generic type `()` for generic parameter + --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:17:13 + | +LL | type Return = impl WithAssoc; + | ^ -error: aborting due to previous error +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0261`. diff --git a/src/test/ui/underscore-lifetime/in-binder.rs b/src/test/ui/underscore-lifetime/in-binder.rs index e4ee5e8cb2741..74dc331b00a5c 100644 --- a/src/test/ui/underscore-lifetime/in-binder.rs +++ b/src/test/ui/underscore-lifetime/in-binder.rs @@ -10,22 +10,22 @@ impl<'_> IceCube<'_> {} //~^ ERROR `'_` cannot be used here struct Struct<'_> { -//~^ ERROR `'_` cannot be used here + //~^ ERROR `'_` cannot be used here v: Vec<&'static char> } enum Enum<'_> { -//~^ ERROR `'_` cannot be used here + //~^ ERROR `'_` cannot be used here Variant } union Union<'_> { -//~^ ERROR `'_` cannot be used here + //~^ ERROR `'_` cannot be used here a: u32 } trait Trait<'_> { -//~^ ERROR `'_` cannot be used here + //~^ ERROR `'_` cannot be used here } fn foo<'_>() { diff --git a/src/test/ui/where-clauses/where-lifetime-resolution.stderr b/src/test/ui/where-clauses/where-lifetime-resolution.stderr index 6c52664154bbf..e8df02fbad62f 100644 --- a/src/test/ui/where-clauses/where-lifetime-resolution.stderr +++ b/src/test/ui/where-clauses/where-lifetime-resolution.stderr @@ -1,20 +1,41 @@ error[E0261]: use of undeclared lifetime name `'a` --> $DIR/where-lifetime-resolution.rs:6:38 | -LL | fn f() where - | - help: consider introducing lifetime `'a` here: `<'a>` -LL | for<'a> dyn Trait1<'a>: Trait1<'a>, // OK LL | (dyn for<'a> Trait1<'a>): Trait1<'a>, | ^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'a` lifetime + | +LL | (dyn for<'a> Trait1<'a>): for<'a> Trait1<'a>, + | +++++++ +help: consider making the bound lifetime-generic with a new `'a` lifetime + | +LL | for<'a> (dyn for<'a> Trait1<'a>): Trait1<'a>, + | +++++++ +help: consider introducing lifetime `'a` here + | +LL | fn f<'a>() where + | ++++ error[E0261]: use of undeclared lifetime name `'b` --> $DIR/where-lifetime-resolution.rs:8:52 | -LL | fn f() where - | - help: consider introducing lifetime `'b` here: `<'b>` -... LL | for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>, | ^^ undeclared lifetime + | +help: consider making the bound lifetime-generic with a new `'b` lifetime + | +LL | for<'a> dyn for<'b> Trait2<'a, 'b>: for<'b> Trait2<'a, 'b>, + | +++++++ +help: consider making the bound lifetime-generic with a new `'b` lifetime + | +LL | for<'b, 'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>, + | +++ +help: consider introducing lifetime `'b` here + | +LL | fn f<'b>() where + | ++++ error: aborting due to 2 previous errors From a9e13fa5533df7fc004aeab00d45822eacb8461e Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 10 Mar 2022 23:12:35 +0100 Subject: [PATCH 6/8] Lint elided lifetimes in path on the AST. --- compiler/rustc_ast_lowering/src/lib.rs | 19 ++- compiler/rustc_ast_lowering/src/path.rs | 39 +----- .../src/diagnostics/region_name.rs | 2 +- compiler/rustc_errors/src/lib.rs | 38 ++--- compiler/rustc_hir/src/hir.rs | 6 +- compiler/rustc_hir/src/intravisit.rs | 2 +- compiler/rustc_lint/src/context.rs | 18 ++- compiler/rustc_lint/src/early.rs | 5 + compiler/rustc_lint_defs/src/lib.rs | 1 + .../rustc_resolve/src/build_reduced_graph.rs | 9 +- compiler/rustc_resolve/src/ident.rs | 2 +- compiler/rustc_resolve/src/late.rs | 132 +++++++++++++++++- .../rustc_resolve/src/late/diagnostics.rs | 36 +---- compiler/rustc_resolve/src/late/lifetimes.rs | 24 ++-- compiler/rustc_resolve/src/lib.rs | 46 +++++- .../async-await/async-fn-path-elision.stderr | 6 +- .../path-elided.stderr | 6 +- .../trait-elided.stderr | 6 +- src/test/ui/issues/issue-10412.stderr | 6 +- src/test/ui/lifetimes/issue-91763.stderr | 6 +- .../force-warn/allowed-by-default-lint.stderr | 6 +- src/test/ui/lint/reasons.rs | 4 +- src/test/ui/lint/reasons.stderr | 8 +- .../wf-in-foreign-fn-decls-issue-80468.stderr | 6 +- 24 files changed, 279 insertions(+), 154 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 5f465124a3168..9cb205074e7ea 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1835,7 +1835,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Output lifetime like `'_`: for (span, node_id) in lifetimes_to_define { let param = this.fresh_lifetime_to_generic_param(span, node_id); - lifetime_params.push((span, hir::LifetimeName::Implicit(false))); + lifetime_params.push((span, hir::LifetimeName::Implicit)); generic_params.push(param); } let generic_params = this.arena.alloc_from_iter(generic_params); @@ -2017,7 +2017,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::Underscore => { + hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => { hir::ParamName::Plain(lt.name.ident()) } hir::LifetimeName::ImplicitObjectLifetimeDefault => { @@ -2397,7 +2397,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { AnonymousLifetimeMode::ReportError => self.new_error_lifetime(None, span), - AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span, false), + AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span), } } @@ -2416,12 +2416,11 @@ 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, param_mode)) + (0..count).map(move |_| self.elided_path_lifetime(span)) } - fn elided_path_lifetime(&mut self, span: Span, param_mode: ParamMode) -> hir::Lifetime { + fn elided_path_lifetime(&mut self, span: Span) -> hir::Lifetime { match self.anonymous_lifetime_mode { AnonymousLifetimeMode::CreateParameter => { // We should have emitted E0726 when processing this path above @@ -2437,7 +2436,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 => { - self.new_implicit_lifetime(span, param_mode == ParamMode::Explicit) + self.new_implicit_lifetime(span) } } } @@ -2480,11 +2479,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { r } - fn new_implicit_lifetime(&mut self, span: Span, missing: bool) -> hir::Lifetime { + fn new_implicit_lifetime(&mut self, span: Span) -> hir::Lifetime { hir::Lifetime { hir_id: self.next_id(), span: self.lower_span(span), - name: hir::LifetimeName::Implicit(missing), + name: hir::LifetimeName::Implicit, } } } @@ -2587,7 +2586,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::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_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index b35e3a071619a..8bf4b8fcc3975 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -290,47 +290,16 @@ 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, param_mode) + .elided_path_lifetimes(elided_lifetime_span, expected_lifetimes) .map(GenericArg::Lifetime) .chain(generic_args.args.into_iter()) .collect(); - // 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, suggestion) = if no_non_lt_args && no_bindings { - // If there are no generic args, our suggestion can include the angle brackets. - (true, format!("<{}>", anon_lt_suggestion)) - } else { - // Otherwise we'll insert a `'_, ` right after the opening bracket. - (false, format!("{}, ", anon_lt_suggestion)) - }; - 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(); + // Late resolver should have issued the error. + self.sess + .delay_span_bug(elided_lifetime_span, "implicit lifetime not allowed here"); } } diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 7742813888e53..459d4a783e40f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -575,7 +575,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span)) } - hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit(_) => { + 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_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 416bc4e2e3bf2..d7c5df7d8e26e 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1511,35 +1511,17 @@ pub fn add_elided_lifetime_in_path_suggestion( path_span: Span, incl_angl_brckt: bool, insertion_span: Span, - anon_lts: String, ) { - let (replace_span, suggestion) = if incl_angl_brckt { - (insertion_span, anon_lts) - } else { - // When possible, prefer a suggestion that replaces the whole - // `Path` expression with `Path<'_, T>`, rather than inserting `'_, ` - // at a point (which makes for an ugly/confusing label) - if let Ok(snippet) = source_map.span_to_snippet(path_span) { - // But our spans can get out of whack due to macros; if the place we think - // we want to insert `'_` isn't even within the path expression's span, we - // should bail out of making any suggestion rather than panicking on a - // subtract-with-overflow or string-slice-out-out-bounds (!) - // FIXME: can we do better? - if insertion_span.lo().0 < path_span.lo().0 { - return; - } - let insertion_index = (insertion_span.lo().0 - path_span.lo().0) as usize; - if insertion_index > snippet.len() { - return; - } - let (before, after) = snippet.split_at(insertion_index); - (path_span, format!("{}{}{}", before, anon_lts, after)) - } else { - (insertion_span, anon_lts) - } - }; - diag.span_suggestion( - replace_span, + diag.span_label(path_span, format!("expected lifetime parameter{}", pluralize!(n))); + if source_map.span_to_snippet(insertion_span).is_err() { + // Do not try to suggest anything if generated by a proc-macro. + return; + } + let anon_lts = vec!["'_"; n].join(", "); + let suggestion = + if incl_angl_brckt { format!("<{}>", anon_lts) } else { format!("{}, ", anon_lts) }; + diag.span_suggestion_verbose( + insertion_span.shrink_to_hi(), &format!("indicate the anonymous lifetime{}", pluralize!(n)), suggestion, Applicability::MachineApplicable, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 83193746432e9..b3de86662eb09 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -95,7 +95,7 @@ pub enum LifetimeName { /// User wrote nothing (e.g., the lifetime in `&u32`). /// /// The bool indicates whether the user should have written something. - Implicit(bool), + Implicit, /// Implicit lifetime in a context like `dyn Foo`. This is /// distinguished from implicit lifetimes elsewhere because the @@ -125,7 +125,7 @@ impl LifetimeName { pub fn ident(&self) -> Ident { match *self { LifetimeName::ImplicitObjectLifetimeDefault - | LifetimeName::Implicit(_) + | LifetimeName::Implicit | LifetimeName::Error => Ident::empty(), LifetimeName::Underscore => Ident::with_dummy_span(kw::UnderscoreLifetime), LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime), @@ -136,7 +136,7 @@ impl LifetimeName { pub fn is_elided(&self) -> bool { match self { LifetimeName::ImplicitObjectLifetimeDefault - | LifetimeName::Implicit(_) + | LifetimeName::Implicit | 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 445b856e513dc..8689e2c2afab3 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -528,7 +528,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::Implicit | LifetimeName::ImplicitObjectLifetimeDefault | LifetimeName::Underscore => {} } diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 3600b6ad21203..152c53dac7ff8 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -21,7 +21,8 @@ use crate::passes::{EarlyLintPassObject, LateLintPassObject}; use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync; -use rustc_errors::{struct_span_err, Applicability, MultiSpan, SuggestionStyle}; +use rustc_errors::{add_elided_lifetime_in_path_suggestion, struct_span_err}; +use rustc_errors::{Applicability, MultiSpan, SuggestionStyle}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def_id::{CrateNum, DefId}; @@ -665,6 +666,21 @@ pub trait LintContext: Sized { ) => { db.span_note(span_def, "the macro is defined here"); } + BuiltinLintDiagnostics::ElidedLifetimesInPaths( + n, + path_span, + incl_angl_brckt, + insertion_span, + ) => { + add_elided_lifetime_in_path_suggestion( + sess.source_map(), + &mut db, + n, + path_span, + incl_angl_brckt, + insertion_span, + ); + } BuiltinLintDiagnostics::UnknownCrateTypes(span, note, sugg) => { db.span_suggestion(span, ¬e, sugg, Applicability::MaybeIncorrect); } diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index e7855f8057c7f..b4262f184c8c4 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -284,6 +284,11 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> ast_visit::walk_path(self, p); } + fn visit_path_segment(&mut self, path_span: Span, s: &'a ast::PathSegment) { + self.check_id(s.id); + ast_visit::walk_path_segment(self, path_span, s); + } + fn visit_attribute(&mut self, attr: &'a ast::Attribute) { run_early_pass!(self, check_attribute, attr); } diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 031b01af5dd95..4debbf26be63b 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -418,6 +418,7 @@ pub enum BuiltinLintDiagnostics { AbsPathWithModule(Span), ProcMacroDeriveResolutionFallback(Span), MacroExpandedMacroExportsAccessedByAbsolutePaths(Span), + ElidedLifetimesInPaths(usize, Span, bool, Span), UnknownCrateTypes(Span, String, String), UnusedImports(String, Vec<(Span, String)>, Option), RedundantImport(Vec<(Span, bool)>, Ident), diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 54e8c03156d55..063b15e643d9c 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -521,11 +521,10 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { // while the current crate doesn't have a valid `crate_name`. if crate_name != kw::Empty { // `crate_name` should not be interpreted as relative. - module_path.push(Segment { - ident: Ident { name: kw::PathRoot, span: source.ident.span }, - id: Some(self.r.next_node_id()), - has_generic_args: false, - }); + module_path.push(Segment::from_ident_and_id( + Ident { name: kw::PathRoot, span: source.ident.span }, + self.r.next_node_id(), + )); source.ident.name = crate_name; } if rename.is_none() { diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 24b6d65698107..84fe0ec83d26c 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1402,7 +1402,7 @@ impl<'a> Resolver<'a> { let mut allow_super = true; let mut second_binding = None; - for (i, &Segment { ident, id, has_generic_args: _ }) in path.iter().enumerate() { + for (i, &Segment { ident, id, .. }) in path.iter().enumerate() { debug!("resolve_path ident {} {:?} {:?}", i, ident, id); let record_segment_res = |this: &mut Self, res| { if finalize.is_some() { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index c6cebd1d3b134..9bc5d63ca179e 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -21,10 +21,11 @@ use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, DefKind, PartialRes, PerNS}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_hir::{PrimTy, TraitCandidate}; +use rustc_middle::ty::DefIdTree; use rustc_middle::{bug, span_bug}; use rustc_session::lint; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::Span; +use rustc_span::{BytePos, Span}; use smallvec::{smallvec, SmallVec}; use rustc_span::source_map::{respan, Spanned}; @@ -1167,6 +1168,134 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.resolve_anonymous_lifetime(<, true); } + #[tracing::instrument(level = "debug", skip(self))] + fn resolve_elided_lifetimes_in_path( + &mut self, + path_id: NodeId, + partial_res: PartialRes, + path: &[Segment], + source: PathSource<'_>, + finalize: Finalize, + ) { + let Some(path_span) = finalize.path_span() else { + return; + }; + let proj_start = path.len() - partial_res.unresolved_segments(); + for (i, segment) in path.iter().enumerate() { + if segment.has_lifetime_args { + continue; + } + let Some(segment_id) = segment.id else { + continue; + }; + + // Figure out if this is a type/trait segment, + // which may need lifetime elision performed. + let type_def_id = match partial_res.base_res() { + Res::Def(DefKind::AssocTy, def_id) if i + 2 == proj_start => { + self.r.parent(def_id).unwrap() + } + Res::Def(DefKind::Variant, def_id) if i + 1 == proj_start => { + self.r.parent(def_id).unwrap() + } + Res::Def(DefKind::Struct, def_id) + | Res::Def(DefKind::Union, def_id) + | Res::Def(DefKind::Enum, def_id) + | Res::Def(DefKind::TyAlias, def_id) + | Res::Def(DefKind::Trait, def_id) + if i + 1 == proj_start => + { + def_id + } + _ => continue, + }; + + let expected_lifetimes = self.r.item_generics_num_lifetimes(type_def_id); + if expected_lifetimes == 0 { + continue; + } + + let missing = match source { + PathSource::Trait(..) | PathSource::TraitItem(..) | PathSource::Type => true, + PathSource::Expr(..) + | PathSource::Pat + | PathSource::Struct + | PathSource::TupleStruct(..) => false, + }; + let mut error = false; + for rib in self.lifetime_ribs.iter().rev() { + match rib.kind { + // In create-parameter mode we error here because we don't want to support + // 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) { ... } + LifetimeRibKind::AnonymousCreateParameter => { + error = true; + break; + } + // `PassThrough` is the normal case. + // `new_error_lifetime`, which would usually be used in the case of `ReportError`, + // is unsuitable here, as these can occur from missing lifetime parameters in a + // `PathSegment`, for which there is no associated `'_` or `&T` with no explicit + // lifetime. Instead, we simply create an implicit lifetime, which will be checked + // later, at which point a suitable error will be emitted. + LifetimeRibKind::AnonymousPassThrough + | LifetimeRibKind::AnonymousReportError + | LifetimeRibKind::Item => break, + _ => {} + } + } + + if !missing { + continue; + } + + let elided_lifetime_span = if segment.has_generic_args { + // If there are brackets, but not generic arguments, then use the opening bracket + segment.args_span.with_hi(segment.args_span.lo() + BytePos(1)) + } else { + // 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) + }; + if error { + let sess = self.r.session; + let mut err = rustc_errors::struct_span_err!( + sess, + path_span, + E0726, + "implicit elided lifetime not allowed here" + ); + rustc_errors::add_elided_lifetime_in_path_suggestion( + sess.source_map(), + &mut err, + expected_lifetimes, + path_span, + !segment.has_generic_args, + elided_lifetime_span, + ); + err.note("assuming a `'static` lifetime..."); + err.emit(); + } else { + self.r.lint_buffer.buffer_lint_with_diagnostic( + lint::builtin::ELIDED_LIFETIMES_IN_PATHS, + segment_id, + elided_lifetime_span, + "hidden lifetime parameters in types are deprecated", + lint::BuiltinLintDiagnostics::ElidedLifetimesInPaths( + expected_lifetimes, + path_span, + !segment.has_generic_args, + elided_lifetime_span, + ), + ); + } + } + } + /// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved /// label and reports an error if the label is not found or is unreachable. fn resolve_label(&self, mut label: Ident) -> Option { @@ -2528,6 +2657,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.r.record_partial_res(id, partial_res); } + self.resolve_elided_lifetimes_in_path(id, partial_res, path, source, finalize); partial_res } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 51a35f8f26db3..0bae141ce26c8 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1986,38 +1986,6 @@ 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::Implicit(true) - }) 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, - 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 // 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. @@ -2452,9 +2420,7 @@ 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::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 72ca9918e122f..d5f2e2db1e39b 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -921,7 +921,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } }); match lifetime.name { - LifetimeName::Implicit(_) => { + 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",); @@ -2955,9 +2955,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let error = loop { match *scope { // Do not assign any resolution, it will be inferred. - Scope::Body { .. } => break Ok(()), + Scope::Body { .. } => return, - Scope::Root => break Err(None), + Scope::Root => break None, Scope::Binder { s, ref lifetimes, scope_type, .. } => { // collect named lifetimes for suggestions @@ -2984,7 +2984,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { self.insert_lifetime(lifetime_ref, lifetime); } - break Ok(()); + return; } Scope::Elision { elide: Elide::Exact(l), .. } => { @@ -2992,7 +2992,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { for lifetime_ref in lifetime_refs { self.insert_lifetime(lifetime_ref, lifetime); } - break Ok(()); + return; } Scope::Elision { elide: Elide::Error(ref e), ref s, .. } => { @@ -3017,10 +3017,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { _ => break, } } - break Err(Some(&e[..])); + break Some(&e[..]); } - Scope::Elision { elide: Elide::Forbid, .. } => break Err(None), + Scope::Elision { elide: Elide::Forbid, .. } => break None, Scope::ObjectLifetimeDefault { s, .. } | Scope::Supertrait { s, .. } @@ -3030,14 +3030,6 @@ 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() { @@ -3174,7 +3166,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { )) .emit(); } - hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit(_) => { + hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit => { self.resolve_lifetime_ref(lt); } hir::LifetimeName::ImplicitObjectLifetimeDefault => { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 7262d150f4c2c..eed54370e2331 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -28,7 +28,7 @@ pub use rustc_hir::def::{Namespace, PerNS}; use rustc_arena::{DroplessArena, TypedArena}; use rustc_ast::node_id::NodeMap; use rustc_ast::{self as ast, NodeId, CRATE_NODE_ID}; -use rustc_ast::{Crate, Expr, ExprKind, LitKind, Path}; +use rustc_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind, Path}; use rustc_ast_lowering::ResolverAstLowering; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::intern::Interned; @@ -283,6 +283,9 @@ pub struct Segment { /// Signals whether this `PathSegment` has generic arguments. Used to avoid providing /// nonsensical suggestions. has_generic_args: bool, + /// Signals whether this `PathSegment` has lifetime arguments. + has_lifetime_args: bool, + args_span: Span, } impl Segment { @@ -291,7 +294,23 @@ impl Segment { } fn from_ident(ident: Ident) -> Segment { - Segment { ident, id: None, has_generic_args: false } + Segment { + ident, + id: None, + has_generic_args: false, + has_lifetime_args: false, + args_span: DUMMY_SP, + } + } + + fn from_ident_and_id(ident: Ident, id: NodeId) -> Segment { + Segment { + ident, + id: Some(id), + has_generic_args: false, + has_lifetime_args: false, + args_span: DUMMY_SP, + } } fn names_to_string(segments: &[Segment]) -> String { @@ -301,7 +320,28 @@ impl Segment { impl<'a> From<&'a ast::PathSegment> for Segment { fn from(seg: &'a ast::PathSegment) -> Segment { - Segment { ident: seg.ident, id: Some(seg.id), has_generic_args: seg.args.is_some() } + let has_generic_args = seg.args.is_some(); + let (args_span, has_lifetime_args) = if let Some(args) = seg.args.as_deref() { + match args { + GenericArgs::AngleBracketed(args) => { + let found_lifetimes = args + .args + .iter() + .any(|arg| matches!(arg, AngleBracketedArg::Arg(GenericArg::Lifetime(_)))); + (args.span, found_lifetimes) + } + GenericArgs::Parenthesized(args) => (args.span, true), + } + } else { + (DUMMY_SP, false) + }; + Segment { + ident: seg.ident, + id: Some(seg.id), + has_generic_args, + has_lifetime_args, + args_span, + } } } diff --git a/src/test/ui/async-await/async-fn-path-elision.stderr b/src/test/ui/async-await/async-fn-path-elision.stderr index 3d18d9c412596..5e0c8c2998910 100644 --- a/src/test/ui/async-await/async-fn-path-elision.stderr +++ b/src/test/ui/async-await/async-fn-path-elision.stderr @@ -2,9 +2,13 @@ error[E0726]: implicit elided lifetime not allowed here --> $DIR/async-fn-path-elision.rs:5:20 | LL | async fn error(lt: HasLifetime) { - | ^^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>` + | ^^^^^^^^^^^ expected lifetime parameter | = note: assuming a `'static` lifetime... +help: indicate the anonymous lifetime + | +LL | async fn error(lt: HasLifetime<'_>) { + | ++++ error: aborting due to previous error diff --git a/src/test/ui/impl-header-lifetime-elision/path-elided.stderr b/src/test/ui/impl-header-lifetime-elision/path-elided.stderr index 90522a885ab90..0b7d3f1e851e3 100644 --- a/src/test/ui/impl-header-lifetime-elision/path-elided.stderr +++ b/src/test/ui/impl-header-lifetime-elision/path-elided.stderr @@ -2,9 +2,13 @@ error[E0726]: implicit elided lifetime not allowed here --> $DIR/path-elided.rs:7:18 | LL | impl MyTrait for Foo { - | ^^^- help: indicate the anonymous lifetime: `<'_>` + | ^^^ expected lifetime parameter | = note: assuming a `'static` lifetime... +help: indicate the anonymous lifetime + | +LL | impl MyTrait for Foo<'_> { + | ++++ error: aborting due to previous error diff --git a/src/test/ui/impl-header-lifetime-elision/trait-elided.stderr b/src/test/ui/impl-header-lifetime-elision/trait-elided.stderr index be918d0a30ce8..412bba6be7167 100644 --- a/src/test/ui/impl-header-lifetime-elision/trait-elided.stderr +++ b/src/test/ui/impl-header-lifetime-elision/trait-elided.stderr @@ -2,9 +2,13 @@ error[E0726]: implicit elided lifetime not allowed here --> $DIR/trait-elided.rs:5:6 | LL | impl MyTrait for u32 {} - | ^^^^^^^- help: indicate the anonymous lifetime: `<'_>` + | ^^^^^^^ expected lifetime parameter | = note: assuming a `'static` lifetime... +help: indicate the anonymous lifetime + | +LL | impl MyTrait<'_> for u32 {} + | ++++ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-10412.stderr b/src/test/ui/issues/issue-10412.stderr index a65005fd72d09..46b9fd541adfa 100644 --- a/src/test/ui/issues/issue-10412.stderr +++ b/src/test/ui/issues/issue-10412.stderr @@ -44,9 +44,13 @@ error[E0726]: implicit elided lifetime not allowed here --> $DIR/issue-10412.rs:7:13 | LL | impl<'self> Serializable for &'self str { - | ^^^^^^^^^^^^^^^^^ help: indicate the anonymous lifetime: `Serializable<'_, str>` + | ^^^^^^^^^^^^^^^^^ expected lifetime parameter | = note: assuming a `'static` lifetime... +help: indicate the anonymous lifetime + | +LL | impl<'self> Serializable<'_, str> for &'self str { + | +++ error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/issue-10412.rs:7:13 diff --git a/src/test/ui/lifetimes/issue-91763.stderr b/src/test/ui/lifetimes/issue-91763.stderr index 1b1912c8e4544..6ccf008c003e4 100644 --- a/src/test/ui/lifetimes/issue-91763.stderr +++ b/src/test/ui/lifetimes/issue-91763.stderr @@ -2,13 +2,17 @@ error: hidden lifetime parameters in types are deprecated --> $DIR/issue-91763.rs:8:20 | LL | fn f() -> Ptr; - | ^ expected named lifetime parameter + | ^ expected lifetime parameter | note: the lint level is defined here --> $DIR/issue-91763.rs:3:9 | LL | #![deny(elided_lifetimes_in_paths)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ +help: indicate the anonymous lifetime + | +LL | fn f() -> Ptr<'_>; + | ++++ error: aborting due to previous error 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 f5e8b41b1634e..ac98b5896ca7b 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,13 +2,13 @@ warning: hidden lifetime parameters in types are deprecated --> $DIR/allowed-by-default-lint.rs:9:12 | LL | fn foo(x: &Foo) {} - | ^^^ expected named lifetime parameter + | ^^^ expected lifetime parameter | = note: requested on the command line with `--force-warn elided-lifetimes-in-paths` -help: consider using the `'_` lifetime +help: indicate the anonymous 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 b1792e2e9cbf8..da1c740c4a344 100644 --- a/src/test/ui/lint/reasons.rs +++ b/src/test/ui/lint/reasons.rs @@ -19,9 +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 expected lifetime parameter //~| NOTE explicit anonymous lifetimes aid - //~| HELP consider using the `'_` lifetime + //~| HELP indicate the anonymous lifetime fmt.debug_struct("CheaterDetectionMechanism").finish() } } diff --git a/src/test/ui/lint/reasons.stderr b/src/test/ui/lint/reasons.stderr index a692d6af703ea..cd8412153f101 100644 --- a/src/test/ui/lint/reasons.stderr +++ b/src/test/ui/lint/reasons.stderr @@ -2,7 +2,9 @@ warning: hidden lifetime parameters in types are deprecated --> $DIR/reasons.rs:20:34 | LL | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - | ^^^^^^^^^ expected named lifetime parameter + | -----^^^^^^^^^ + | | + | expected lifetime parameter | = note: explicit anonymous lifetimes aid reasoning about ownership note: the lint level is defined here @@ -10,10 +12,10 @@ note: the lint level is defined here | LL | #![warn(elided_lifetimes_in_paths, | ^^^^^^^^^^^^^^^^^^^^^^^^^ -help: consider using the `'_` lifetime +help: indicate the anonymous 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 diff --git a/src/test/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr b/src/test/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr index ba624507c21f0..16d198725523e 100644 --- a/src/test/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr +++ b/src/test/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr @@ -2,9 +2,13 @@ error[E0726]: implicit elided lifetime not allowed here --> $DIR/wf-in-foreign-fn-decls-issue-80468.rs:13:16 | LL | impl Trait for Ref {} - | ^^^- help: indicate the anonymous lifetime: `<'_>` + | ^^^ expected lifetime parameter | = note: assuming a `'static` lifetime... +help: indicate the anonymous lifetime + | +LL | impl Trait for Ref<'_> {} + | ++++ error: incompatible lifetime on type --> $DIR/wf-in-foreign-fn-decls-issue-80468.rs:16:21 From 35eac359c9b4a26dd03c651c71e094338cad4994 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Fri, 1 Apr 2022 19:18:10 +0200 Subject: [PATCH 7/8] Bless clippy. --- src/tools/clippy/tests/ui/unused_unit.stderr | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/tools/clippy/tests/ui/unused_unit.stderr b/src/tools/clippy/tests/ui/unused_unit.stderr index 02038b5fb6b5a..0d2cb77855be1 100644 --- a/src/tools/clippy/tests/ui/unused_unit.stderr +++ b/src/tools/clippy/tests/ui/unused_unit.stderr @@ -1,8 +1,8 @@ error: unneeded unit return type - --> $DIR/unused_unit.rs:19:28 + --> $DIR/unused_unit.rs:19:58 | LL | pub fn get_unit (), G>(&self, f: F, _g: G) -> () - | ^^^^^^ help: remove the `-> ()` + | ^^^^^^ help: remove the `-> ()` | note: the lint level is defined here --> $DIR/unused_unit.rs:12:9 @@ -11,16 +11,16 @@ LL | #![deny(clippy::unused_unit)] | ^^^^^^^^^^^^^^^^^^^ error: unneeded unit return type - --> $DIR/unused_unit.rs:20:18 + --> $DIR/unused_unit.rs:19:28 | -LL | where G: Fn() -> () { - | ^^^^^^ help: remove the `-> ()` +LL | pub fn get_unit (), G>(&self, f: F, _g: G) -> () + | ^^^^^^ help: remove the `-> ()` error: unneeded unit return type - --> $DIR/unused_unit.rs:19:58 + --> $DIR/unused_unit.rs:20:18 | -LL | pub fn get_unit (), G>(&self, f: F, _g: G) -> () - | ^^^^^^ help: remove the `-> ()` +LL | where G: Fn() -> () { + | ^^^^^^ help: remove the `-> ()` error: unneeded unit return type --> $DIR/unused_unit.rs:21:26 From e628df9b0b0310fb293c75e75ad19c72f92381f8 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 17 Apr 2022 12:41:49 +0200 Subject: [PATCH 8/8] Bless nll test. --- .../missing-lifetimes-in-signature.nll.stderr | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr new file mode 100644 index 0000000000000..0ae629676fec7 --- /dev/null +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr @@ -0,0 +1,106 @@ +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/missing-lifetimes-in-signature.rs:38:11 + | +LL | fn baz(g: G, dest: &mut T) -> impl FnOnce() + '_ + | - ^^ undeclared lifetime + | | + | help: consider introducing lifetime `'a` here: `'a,` + +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds + --> $DIR/missing-lifetimes-in-signature.rs:19:5 + | +LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() + | ------ hidden type `[closure@$DIR/missing-lifetimes-in-signature.rs:19:5: 22:6]` captures the anonymous lifetime defined here +... +LL | / move || { +LL | | +LL | | *dest = g.get(); +LL | | } + | |_____^ + | +help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound + | +LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() + '_ + | ++++ + +error[E0311]: the parameter type `G` may not live long enough + --> $DIR/missing-lifetimes-in-signature.rs:32:5 + | +LL | / move || { +LL | | *dest = g.get(); +LL | | } + | |_____^ + | +note: the parameter type `G` must be valid for the anonymous lifetime defined here... + --> $DIR/missing-lifetimes-in-signature.rs:26:26 + | +LL | fn bar(g: G, dest: &mut T) -> impl FnOnce() + '_ + | ^^^^^^ + +error[E0311]: the parameter type `G` may not live long enough + --> $DIR/missing-lifetimes-in-signature.rs:55:5 + | +LL | / move || { +LL | | *dest = g.get(); +LL | | } + | |_____^ + | +note: the parameter type `G` must be valid for the anonymous lifetime defined here... + --> $DIR/missing-lifetimes-in-signature.rs:49:34 + | +LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + | ^^^^^^ + +error[E0311]: the parameter type `G` may not live long enough + --> $DIR/missing-lifetimes-in-signature.rs:65:9 + | +LL | / move || { +LL | | *dest = g.get(); +LL | | } + | |_________^ + | +note: the parameter type `G` must be valid for the anonymous lifetime defined here... + --> $DIR/missing-lifetimes-in-signature.rs:62:47 + | +LL | fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { + | ^^^^^^ + +error[E0311]: the parameter type `G` may not live long enough + --> $DIR/missing-lifetimes-in-signature.rs:77:5 + | +LL | / move || { +LL | | *dest = g.get(); +LL | | } + | |_____^ + | +note: the parameter type `G` must be valid for the anonymous lifetime defined here... + --> $DIR/missing-lifetimes-in-signature.rs:72:34 + | +LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a + | ^^^^^^ + +error[E0621]: explicit lifetime required in the type of `dest` + --> $DIR/missing-lifetimes-in-signature.rs:77:5 + | +LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a + | ------ help: add explicit lifetime `'a` to the type of `dest`: `&'a mut T` +... +LL | / move || { +LL | | *dest = g.get(); +LL | | } + | |_____^ lifetime `'a` required + +error[E0309]: the parameter type `G` may not live long enough + --> $DIR/missing-lifetimes-in-signature.rs:89:5 + | +LL | / move || { +LL | | *dest = g.get(); +LL | | } + | |_____^ + | + = help: consider adding an explicit lifetime bound `G: 'a`... + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0261, E0309, E0621, E0700. +For more information about an error, try `rustc --explain E0261`.