diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 73d6566e3cd..533302a758f 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -12,6 +12,10 @@ use crate::{path_names_to_string, BindingError, Finalize, LexicalScopeBinding}; use crate::{Module, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult}; use crate::{ResolutionError, Resolver, Segment, UseError}; +use diagnostics::{ + original_label, original_lifetime, original_lifetime_param, shadower_label, shadower_lifetime, +}; + use rustc_ast::ptr::P; use rustc_ast::visit::{self, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor}; use rustc_ast::*; @@ -172,6 +176,23 @@ impl RibKind<'_> { AssocItemRibKind | ItemRibKind(_) | ForwardGenericParamBanRibKind => true, } } + + /// This rib forbids referring to labels defined in upwards ribs. + fn is_label_barrier(self) -> bool { + match self { + NormalRibKind | MacroDefinition(..) => false, + + AssocItemRibKind + | ClosureOrAsyncRibKind + | FnItemRibKind + | ItemRibKind(..) + | ConstantItemRibKind(..) + | ModuleRibKind(..) + | ForwardGenericParamBanRibKind + | ConstParamTyRibKind + | InlineAsmSymRibKind => true, + } + } } /// A single local scope. @@ -732,7 +753,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { // Create a value rib for the function. self.with_rib(ValueNS, rib_kind, |this| { // Create a label rib for the function. - this.with_label_rib(rib_kind, |this| { + this.with_label_rib(FnItemRibKind, |this| { let async_node_id = fn_kind.header().and_then(|h| h.asyncness.opt_return_id()); if let FnKind::Fn(_, _, _, _, generics, _) = fn_kind { @@ -1585,22 +1606,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { let ribs = &self.label_ribs[rib_index + 1..]; for rib in ribs { - match rib.kind { - NormalRibKind | MacroDefinition(..) => { - // Nothing to do. Continue. - } - - AssocItemRibKind - | ClosureOrAsyncRibKind - | FnItemRibKind - | ItemRibKind(..) - | ConstantItemRibKind(..) - | ModuleRibKind(..) - | ForwardGenericParamBanRibKind - | ConstParamTyRibKind - | InlineAsmSymRibKind => { - return false; - } + if rib.kind.is_label_barrier() { + return false; } } @@ -1895,6 +1902,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { let mut function_value_rib = Rib::new(kind); let mut function_lifetime_rib = LifetimeRib::new(lifetime_kind); let mut seen_bindings = FxHashMap::default(); + let mut seen_lifetimes = FxHashMap::default(); // We also can't shadow bindings from the parent item if let AssocItemRibKind = kind { @@ -1910,20 +1918,52 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { add_bindings_for_ns(TypeNS); } + // Forbid shadowing lifetime bindings + for rib in self.lifetime_ribs.iter().rev() { + seen_lifetimes.extend( + rib.bindings.iter().map(|(ident, _)| (*ident, original_lifetime(ident.span))), + ); + if let LifetimeRibKind::Item = rib.kind { + break; + } + } + for rib in self.label_ribs.iter().rev() { + if rib.kind.is_label_barrier() { + break; + } + seen_lifetimes + .extend(rib.bindings.iter().map(|(ident, _)| (*ident, original_label(ident.span)))); + } + for param in params { let ident = param.ident.normalize_to_macros_2_0(); debug!("with_generic_param_rib: {}", param.id); - match seen_bindings.entry(ident) { - Entry::Occupied(entry) => { - let span = *entry.get(); - let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, span); - if !matches!(param.kind, GenericParamKind::Lifetime) { - self.report_error(param.ident.span, err); + if let GenericParamKind::Lifetime = param.kind { + match seen_lifetimes.entry(ident) { + Entry::Occupied(entry) => { + let original = *entry.get(); + diagnostics::signal_shadowing_problem( + self.r.session, + ident.name, + original, + shadower_lifetime(param.ident.span), + ) + } + Entry::Vacant(entry) => { + entry.insert(original_lifetime_param(param.ident.span)); } } - Entry::Vacant(entry) => { - entry.insert(param.ident.span); + } else { + match seen_bindings.entry(ident) { + Entry::Occupied(entry) => { + let span = *entry.get(); + let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, span); + self.report_error(param.ident.span, err); + } + Entry::Vacant(entry) => { + entry.insert(param.ident.span); + } } } @@ -3114,8 +3154,35 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { if label.ident.as_str().as_bytes()[1] != b'_' { self.diagnostic_metadata.unused_labels.insert(id, label.ident.span); } + + // Forbid shadowing lifetime bindings + let ident = label.ident.normalize_to_macro_rules(); + for rib in self.lifetime_ribs.iter().rev() { + if let Some((orig_ident, _)) = rib.bindings.get_key_value(&ident) { + diagnostics::signal_shadowing_problem( + self.r.session, + label.ident.name, + original_lifetime(orig_ident.span), + shadower_label(label.ident.span), + ) + } + } + for rib in self.label_ribs.iter_mut().rev() { + if let Some((orig_ident, _)) = rib.bindings.get_key_value(&ident) { + diagnostics::signal_shadowing_problem( + self.r.session, + label.ident.name, + original_label(orig_ident.span), + shadower_label(label.ident.span), + ) + } + if rib.kind.is_label_barrier() { + rib.bindings.insert(ident, id); + break; + } + } + self.with_label_rib(NormalRibKind, |this| { - let ident = label.ident.normalize_to_macro_rules(); this.label_ribs.last_mut().unwrap().bindings.insert(ident, id); f(this); }); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index a6a04ac9ea6..b77bcaad354 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -25,6 +25,7 @@ use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::PrimTy; use rustc_session::lint; use rustc_session::parse::feature_err; +use rustc_session::Session; use rustc_span::edition::Edition; use rustc_span::hygiene::MacroKind; use rustc_span::lev_distance::find_best_match_for_name; @@ -2036,6 +2037,87 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { } } +#[derive(Copy, Clone, PartialEq)] +enum ShadowKind { + Label, + Lifetime, +} +#[derive(Copy, Clone)] +pub struct Original { + kind: ShadowKind, + span: Span, + param: bool, +} +#[derive(Copy, Clone)] +pub struct Shadower { + kind: ShadowKind, + span: Span, +} + +pub fn original_label(span: Span) -> Original { + Original { kind: ShadowKind::Label, span, param: false } +} +pub fn shadower_label(span: Span) -> Shadower { + Shadower { kind: ShadowKind::Label, span } +} +pub fn original_lifetime(span: Span) -> Original { + Original { kind: ShadowKind::Lifetime, span, param: false } +} +pub fn original_lifetime_param(span: Span) -> Original { + Original { kind: ShadowKind::Lifetime, span, param: true } +} +pub fn shadower_lifetime(span: Span) -> Shadower { + Shadower { kind: ShadowKind::Lifetime, span } +} + +impl ShadowKind { + fn desc(&self) -> &'static str { + match *self { + ShadowKind::Label => "label", + ShadowKind::Lifetime => "lifetime", + } + } +} + +pub fn signal_shadowing_problem(sess: &Session, name: Symbol, orig: Original, shadower: Shadower) { + let mut err = if let (ShadowKind::Lifetime, ShadowKind::Lifetime) = (orig.kind, shadower.kind) { + // lifetime/lifetime shadowing is an error + if orig.param { + struct_span_err!( + sess, + shadower.span, + E0263, + "lifetime name `{}` declared twice in the same scope", + name, + ) + } else { + struct_span_err!( + sess, + shadower.span, + E0496, + "lifetime name `{}` shadows a lifetime name that is already in scope", + name, + ) + } + .forget_guarantee() + } else { + // shadowing involving a label is only a warning, due to issues with + // labels and lifetimes not being macro-hygienic. + sess.struct_span_warn( + shadower.span, + &format!( + "{} name `{}` shadows a {} name that is already in scope", + shadower.kind.desc(), + name, + orig.kind.desc() + ), + ) + }; + err.span_label(orig.span, "first declared here"); + err.span_label(shadower.span, format!("{} `{}` already in scope", orig.kind.desc(), name)); + err.emit(); +} + impl<'tcx> LifetimeContext<'_, 'tcx> { pub(crate) fn report_missing_lifetime_specifiers( &self, diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 2fe65441ac9..59c2db25b8e 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -23,7 +23,7 @@ use rustc_middle::middle::resolve_lifetime::*; use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_span::def_id::DefId; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; +use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; use std::borrow::Cow; use std::cell::Cell; @@ -161,9 +161,6 @@ pub(crate) struct LifetimeContext<'a, 'tcx> { /// we eventually need lifetimes resolve for trait items. trait_definition_only: bool, - /// List of labels in the function/method currently under analysis. - labels_in_fn: Vec, - /// Cache for cross-crate per-definition object lifetime defaults. xcrate_object_lifetime_defaults: DefIdMap>, @@ -434,7 +431,6 @@ fn do_resolve( map: &mut named_region_map, scope: ROOT_SCOPE, trait_definition_only, - labels_in_fn: vec![], xcrate_object_lifetime_defaults: Default::default(), missing_named_lifetime_spots: vec![], }; @@ -641,14 +637,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } fn visit_nested_body(&mut self, body: hir::BodyId) { - // Each body has their own set of labels, save labels. - let saved = take(&mut self.labels_in_fn); let body = self.tcx.hir().body(body); - extract_labels(self, body); - self.with(Scope::Body { id: body.id(), s: self.scope }, |_, this| { + self.with(Scope::Body { id: body.id(), s: self.scope }, |this| { this.visit_body(body); }); - self.labels_in_fn = saved; } fn visit_fn( @@ -683,9 +675,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { scope_type: BinderScopeType::Normal, allow_late_bound: true, }; - self.with(scope, move |_old_scope, this| { - intravisit::walk_fn(this, fk, fd, b, s, hir_id) - }); + self.with(scope, move |this| intravisit::walk_fn(this, fk, fd, b, s, hir_id)); } } } @@ -720,7 +710,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => { // No lifetime parameters, but implied 'static. let scope = Scope::Elision { elide: Elide::Exact(Region::Static), s: ROOT_SCOPE }; - self.with(scope, |_, this| intravisit::walk_item(this, item)); + self.with(scope, |this| intravisit::walk_item(this, item)); } hir::ItemKind::OpaqueTy(hir::OpaqueTy { .. }) => { // Opaque types are visited when we visit the @@ -807,10 +797,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { s: ROOT_SCOPE, allow_late_bound: false, }; - self.with(scope, |old_scope, this| { - this.check_lifetime_params(old_scope, &generics.params); + self.with(scope, |this| { let scope = Scope::TraitRefBoundary { s: this.scope }; - this.with(scope, |_, this| { + this.with(scope, |this| { intravisit::walk_item(this, item); }); }); @@ -873,10 +862,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { scope_type: BinderScopeType::Normal, allow_late_bound: true, }; - self.with(scope, |old_scope, this| { + self.with(scope, |this| { // a bare fn has no bounds, so everything // contained within is scoped within its binder. - this.check_lifetime_params(old_scope, &c.generic_params); intravisit::walk_ty(this, ty); }); self.missing_named_lifetime_spots.pop(); @@ -884,7 +872,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir::TyKind::TraitObject(bounds, ref lifetime, _) => { debug!(?bounds, ?lifetime, "TraitObject"); let scope = Scope::TraitRefBoundary { s: self.scope }; - self.with(scope, |_, this| { + self.with(scope, |this| { for bound in bounds { this.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); } @@ -923,7 +911,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { lifetime: self.map.defs.get(&lifetime_ref.hir_id).cloned(), s: self.scope, }; - self.with(scope, |_, this| this.visit_ty(&mt.ty)); + self.with(scope, |this| this.visit_ty(&mt.ty)); } hir::TyKind::OpaqueDef(item_id, lifetimes) => { // Resolve the lifetimes in the bounds to the lifetime defs in the generics. @@ -944,9 +932,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // Elided lifetimes are not allowed in non-return // position impl Trait let scope = Scope::TraitRefBoundary { s: self.scope }; - self.with(scope, |_, this| { + self.with(scope, |this| { let scope = Scope::Elision { elide: Elide::Forbid, s: this.scope }; - this.with(scope, |_, this| { + this.with(scope, |this| { intravisit::walk_item(this, opaque_ty); }) }); @@ -1052,7 +1040,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { if let Some(elision_region) = elision { let scope = Scope::Elision { elide: Elide::Exact(elision_region), s: self.scope }; - self.with(scope, |_old_scope, this| { + self.with(scope, |this| { let scope = Scope::Binder { hir_id: ty.hir_id, lifetimes, @@ -1062,10 +1050,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { scope_type: BinderScopeType::Normal, allow_late_bound: false, }; - this.with(scope, |_old_scope, this| { + this.with(scope, |this| { this.visit_generics(generics); let scope = Scope::TraitRefBoundary { s: this.scope }; - this.with(scope, |_, this| { + this.with(scope, |this| { for bound in bounds { this.visit_param_bound(bound); } @@ -1082,9 +1070,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { scope_type: BinderScopeType::Normal, allow_late_bound: false, }; - self.with(scope, |_old_scope, this| { + self.with(scope, |this| { let scope = Scope::TraitRefBoundary { s: this.scope }; - this.with(scope, |_, this| { + this.with(scope, |this| { this.visit_generics(generics); for bound in bounds { this.visit_param_bound(bound); @@ -1141,10 +1129,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { scope_type: BinderScopeType::Normal, allow_late_bound: false, }; - self.with(scope, |old_scope, this| { - this.check_lifetime_params(old_scope, &generics.params); + self.with(scope, |this| { let scope = Scope::TraitRefBoundary { s: this.scope }; - this.with(scope, |_, this| { + this.with(scope, |this| { this.visit_generics(generics); for bound in bounds { this.visit_param_bound(bound); @@ -1210,10 +1197,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { scope_type: BinderScopeType::Normal, allow_late_bound: true, }; - self.with(scope, |old_scope, this| { - this.check_lifetime_params(old_scope, &generics.params); + self.with(scope, |this| { let scope = Scope::TraitRefBoundary { s: this.scope }; - this.with(scope, |_, this| { + this.with(scope, |this| { this.visit_generics(generics); this.visit_ty(ty); }) @@ -1300,7 +1286,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) { let scope = Scope::TraitRefBoundary { s: self.scope }; - self.with(scope, |_, this| { + self.with(scope, |this| { for param in generics.params { match param.kind { GenericParamKind::Lifetime { .. } => {} @@ -1354,8 +1340,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { scope_type: BinderScopeType::Normal, allow_late_bound: true, }; - this.with(scope, |old_scope, this| { - this.check_lifetime_params(old_scope, &bound_generic_params); + this.with(scope, |this| { this.visit_ty(&bounded_ty); walk_list!(this, visit_param_bound, bounds); }) @@ -1427,7 +1412,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { scope_type, allow_late_bound: true, }; - self.with(scope, |_, this| { + self.with(scope, |this| { intravisit::walk_param_bound(this, bound); }); } @@ -1479,8 +1464,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { scope_type, allow_late_bound: true, }; - self.with(scope, |old_scope, this| { - this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params); + self.with(scope, |this| { walk_list!(this, visit_generic_param, trait_ref.bound_generic_params); this.visit_trait_ref(&trait_ref.trait_ref); }); @@ -1491,154 +1475,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } -#[derive(Copy, Clone, PartialEq)] -enum ShadowKind { - Label, - Lifetime, -} -struct Original { - kind: ShadowKind, - span: Span, -} -struct Shadower { - kind: ShadowKind, - span: Span, -} - -fn original_label(span: Span) -> Original { - Original { kind: ShadowKind::Label, span } -} -fn shadower_label(span: Span) -> Shadower { - Shadower { kind: ShadowKind::Label, span } -} -fn original_lifetime(span: Span) -> Original { - Original { kind: ShadowKind::Lifetime, span } -} -fn shadower_lifetime(param: &hir::GenericParam<'_>) -> Shadower { - Shadower { kind: ShadowKind::Lifetime, span: param.span } -} - -impl ShadowKind { - fn desc(&self) -> &'static str { - match *self { - ShadowKind::Label => "label", - ShadowKind::Lifetime => "lifetime", - } - } -} - -fn signal_shadowing_problem(tcx: TyCtxt<'_>, name: Symbol, orig: Original, shadower: Shadower) { - let mut err = if let (ShadowKind::Lifetime, ShadowKind::Lifetime) = (orig.kind, shadower.kind) { - // lifetime/lifetime shadowing is an error - struct_span_err!( - tcx.sess, - shadower.span, - E0496, - "{} name `{}` shadows a \ - {} name that is already in scope", - shadower.kind.desc(), - name, - orig.kind.desc() - ) - .forget_guarantee() - } else { - // shadowing involving a label is only a warning, due to issues with - // labels and lifetimes not being macro-hygienic. - tcx.sess.struct_span_warn( - shadower.span, - &format!( - "{} name `{}` shadows a \ - {} name that is already in scope", - shadower.kind.desc(), - name, - orig.kind.desc() - ), - ) - }; - err.span_label(orig.span, "first declared here"); - err.span_label(shadower.span, format!("{} `{}` already in scope", orig.kind.desc(), name)); - err.emit(); -} - -// Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning -// if one of the label shadows a lifetime or another label. -fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body<'_>) { - struct GatherLabels<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - scope: ScopeRef<'a>, - labels_in_fn: &'a mut Vec, - } - - let mut gather = - GatherLabels { tcx: ctxt.tcx, scope: ctxt.scope, labels_in_fn: &mut ctxt.labels_in_fn }; - gather.visit_body(body); - - impl<'v, 'a, 'tcx> Visitor<'v> for GatherLabels<'a, 'tcx> { - fn visit_expr(&mut self, ex: &hir::Expr<'_>) { - if let Some(label) = expression_label(ex) { - for prior_label in &self.labels_in_fn[..] { - // FIXME (#24278): non-hygienic comparison - if label.name == prior_label.name { - signal_shadowing_problem( - self.tcx, - label.name, - original_label(prior_label.span), - shadower_label(label.span), - ); - } - } - - check_if_label_shadows_lifetime(self.tcx, self.scope, label); - - self.labels_in_fn.push(label); - } - intravisit::walk_expr(self, ex) - } - } - - fn expression_label(ex: &hir::Expr<'_>) -> Option { - match ex.kind { - hir::ExprKind::Loop(_, Some(label), ..) => Some(label.ident), - hir::ExprKind::Block(_, Some(label)) => Some(label.ident), - _ => None, - } - } - - fn check_if_label_shadows_lifetime(tcx: TyCtxt<'_>, mut scope: ScopeRef<'_>, label: Ident) { - loop { - match *scope { - Scope::Body { s, .. } - | Scope::Elision { s, .. } - | Scope::ObjectLifetimeDefault { s, .. } - | Scope::Supertrait { s, .. } - | Scope::TraitRefBoundary { s, .. } => { - scope = s; - } - - Scope::Root => { - return; - } - - Scope::Binder { ref lifetimes, s, .. } => { - // FIXME (#24278): non-hygienic comparison - if let Some(def) = - lifetimes.get(&hir::ParamName::Plain(label.normalize_to_macros_2_0())) - { - signal_shadowing_problem( - tcx, - label.name, - original_lifetime(tcx.def_span(def.id().unwrap().expect_local())), - shadower_label(label.span), - ); - return; - } - scope = s; - } - } - } - } -} - fn compute_object_lifetime_defaults<'tcx>( tcx: TyCtxt<'tcx>, item: &hir::Item<'_>, @@ -1774,10 +1610,9 @@ fn object_lifetime_defaults_for_item<'tcx>( impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { fn with(&mut self, wrap_scope: Scope<'_>, f: F) where - F: for<'b> FnOnce(ScopeRef<'_>, &mut LifetimeContext<'b, 'tcx>), + F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>), { let LifetimeContext { tcx, map, .. } = self; - let labels_in_fn = take(&mut self.labels_in_fn); let xcrate_object_lifetime_defaults = take(&mut self.xcrate_object_lifetime_defaults); let missing_named_lifetime_spots = take(&mut self.missing_named_lifetime_spots); let mut this = LifetimeContext { @@ -1785,16 +1620,14 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { map, scope: &wrap_scope, trait_definition_only: self.trait_definition_only, - labels_in_fn, xcrate_object_lifetime_defaults, missing_named_lifetime_spots, }; let span = tracing::debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope)); { let _enter = span.enter(); - f(self.scope, &mut this); + f(&mut this); } - self.labels_in_fn = this.labels_in_fn; self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults; self.missing_named_lifetime_spots = this.missing_named_lifetime_spots; } @@ -1891,10 +1724,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { scope_type: BinderScopeType::Normal, allow_late_bound: true, }; - self.with(scope, move |old_scope, this| { - this.check_lifetime_params(old_scope, &generics.params); - walk(this); - }); + self.with(scope, walk); } fn next_early_index_helper(&self, only_opaque_type_parent: bool) -> u32 { @@ -2165,7 +1995,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { GenericArg::Type(ty) => { if let Some(<) = object_lifetime_defaults.get(i) { let scope = Scope::ObjectLifetimeDefault { lifetime: lt, s: self.scope }; - self.with(scope, |_, this| this.visit_ty(ty)); + self.with(scope, |this| this.visit_ty(ty)); } else { self.visit_ty(ty); } @@ -2222,15 +2052,15 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { type_def_id, binding.ident, ); - self.with(scope, |_, this| { + self.with(scope, |this| { let scope = Scope::Supertrait { lifetimes: lifetimes.unwrap_or_default(), s: this.scope, }; - this.with(scope, |_, this| this.visit_assoc_type_binding(binding)); + this.with(scope, |this| this.visit_assoc_type_binding(binding)); }); } else { - self.with(scope, |_, this| this.visit_assoc_type_binding(binding)); + self.with(scope, |this| this.visit_assoc_type_binding(binding)); } } } @@ -2346,7 +2176,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { elide: Elide::FreshLateAnon(named_late_bound_vars, Cell::new(0)), s: self.scope, }; - self.with(arg_scope, |_, this| { + self.with(arg_scope, |this| { for input in inputs { this.visit_ty(input); } @@ -2466,7 +2296,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { visitor.visit_ty(&inputs[0]); if let Set1::One(lifetime) = visitor.lifetime { let scope = Scope::Elision { elide: Elide::Exact(lifetime), s: self.scope }; - self.with(scope, |_, this| this.visit_ty(output)); + self.with(scope, |this| this.visit_ty(output)); return; } } @@ -2517,7 +2347,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { debug!(?elide); let scope = Scope::Elision { elide, s: self.scope }; - self.with(scope, |_, this| this.visit_ty(output)); + self.with(scope, |this| this.visit_ty(output)); struct GatherLifetimes<'a> { map: &'a NamedRegionMap, @@ -2789,101 +2619,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth)); } - fn check_lifetime_params( - &mut self, - old_scope: ScopeRef<'_>, - params: &'tcx [hir::GenericParam<'tcx>], - ) { - let lifetimes: Vec<_> = params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - Some((param, param.name.normalize_to_macros_2_0())) - } - _ => None, - }) - .collect(); - for (i, (lifetime_i, lifetime_i_name)) in lifetimes.iter().enumerate() { - if let hir::ParamName::Plain(_) = lifetime_i_name { - let name = lifetime_i_name.ident().name; - if name == kw::UnderscoreLifetime || name == kw::StaticLifetime { - self.tcx.sess.delay_span_bug( - lifetime_i.span, - &format!("invalid lifetime parameter name: `{}`", lifetime_i.name.ident()), - ); - } - } - - // It is a hard error to shadow a lifetime within the same scope. - for (lifetime_j, lifetime_j_name) in lifetimes.iter().skip(i + 1) { - if lifetime_i_name == lifetime_j_name { - struct_span_err!( - self.tcx.sess, - lifetime_j.span, - E0263, - "lifetime name `{}` declared twice in the same scope", - lifetime_j.name.ident() - ) - .span_label(lifetime_j.span, "declared twice") - .span_label(lifetime_i.span, "previous declaration here") - .emit(); - } - } - - // It is a soft error to shadow a lifetime within a parent scope. - self.check_lifetime_param_for_shadowing(old_scope, &lifetime_i); - } - } - - fn check_lifetime_param_for_shadowing( - &self, - mut old_scope: ScopeRef<'_>, - param: &'tcx hir::GenericParam<'tcx>, - ) { - for label in &self.labels_in_fn { - // FIXME (#24278): non-hygienic comparison - if param.name.ident().name == label.name { - signal_shadowing_problem( - self.tcx, - label.name, - original_label(label.span), - shadower_lifetime(¶m), - ); - return; - } - } - - loop { - match *old_scope { - Scope::Body { s, .. } - | Scope::Elision { s, .. } - | Scope::ObjectLifetimeDefault { s, .. } - | Scope::Supertrait { s, .. } - | Scope::TraitRefBoundary { s, .. } => { - old_scope = s; - } - - Scope::Root => { - return; - } - - Scope::Binder { ref lifetimes, s, .. } => { - if let Some(&def) = lifetimes.get(¶m.name.normalize_to_macros_2_0()) { - signal_shadowing_problem( - self.tcx, - param.name.ident().name, - original_lifetime(self.tcx.def_span(def.id().unwrap())), - shadower_lifetime(¶m), - ); - return; - } - - old_scope = s; - } - } - } - } - #[tracing::instrument(level = "debug", skip(self))] fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) { debug!(