From 257d8fce3e38177c3cc357f1ce23db87b69e1682 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 21 Apr 2022 19:48:40 +0200 Subject: [PATCH] Do not report mixed label/lifetime shadowing. --- compiler/rustc_resolve/src/late.rs | 50 ++------ .../rustc_resolve/src/late/diagnostics.rs | 108 ++++++------------ 2 files changed, 46 insertions(+), 112 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 533302a758f..efdedbebbea 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -12,10 +12,6 @@ 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::*; @@ -1902,6 +1898,8 @@ 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(); + // Store all seen lifetimes names, and whether they were created in the currently processed + // parameter set. let mut seen_lifetimes = FxHashMap::default(); // We also can't shadow bindings from the parent item @@ -1920,20 +1918,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // 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))), - ); + seen_lifetimes.extend(rib.bindings.iter().map(|(ident, _)| (*ident, false))); 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(); @@ -1942,16 +1931,17 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { if let GenericParamKind::Lifetime = param.kind { match seen_lifetimes.entry(ident) { Entry::Occupied(entry) => { - let original = *entry.get(); - diagnostics::signal_shadowing_problem( + let original = *entry.key(); + let orig_is_param = *entry.get(); + diagnostics::signal_lifetime_shadowing( self.r.session, - ident.name, original, - shadower_lifetime(param.ident.span), - ) + param.ident, + orig_is_param, + ); } Entry::Vacant(entry) => { - entry.insert(original_lifetime_param(param.ident.span)); + entry.insert(true); } } } else { @@ -3155,26 +3145,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { 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 let Some((&orig_ident, _)) = rib.bindings.get_key_value(&ident) { + diagnostics::signal_label_shadowing(self.r.session, orig_ident, label.ident) } if rib.kind.is_label_barrier() { rib.bindings.insert(ident, id); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index b77bcaad354..552102be92c 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2037,84 +2037,44 @@ 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( +/// Report lifetime/lifetime shadowing as an error. +pub fn signal_lifetime_shadowing( + sess: &Session, + orig: Ident, + shadower: Ident, + orig_is_param: bool, +) { + let mut err = if orig_is_param { + struct_span_err!( + sess, shadower.span, - &format!( - "{} name `{}` shadows a {} name that is already in scope", - shadower.kind.desc(), - name, - orig.kind.desc() - ), + E0263, + "lifetime name `{}` declared twice in the same scope", + orig.name, + ) + } else { + struct_span_err!( + sess, + shadower.span, + E0496, + "lifetime name `{}` shadows a lifetime name that is already in scope", + orig.name, ) }; err.span_label(orig.span, "first declared here"); - err.span_label(shadower.span, format!("{} `{}` already in scope", orig.kind.desc(), name)); + err.span_label(shadower.span, format!("lifetime `{}` already in scope", orig.name)); + err.emit(); +} + +/// Shadowing involving a label is only a warning, due to issues with +/// labels and lifetimes not being macro-hygienic. +pub fn signal_label_shadowing(sess: &Session, orig: Ident, shadower: Ident) { + let mut err = sess.struct_span_warn( + shadower.span, + &format!("label name `{}` shadows a label name that is already in scope", orig.name), + ); + err.span_label(orig.span, "first declared here"); + err.span_label(shadower.span, format!("label `{}` already in scope", orig.name)); err.emit(); }