]> git.lizzy.rs Git - rust.git/blobdiff - compiler/rustc_resolve/src/late.rs
Diagnose shadowing on AST.
[rust.git] / compiler / rustc_resolve / src / late.rs
index 73d6566e3cd977655f2c1b5c07476aefe8aef1c3..533302a758f17f763ae3f78d7bd3554cc41c3001 100644 (file)
 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 @@ pub(crate) fn contains_params(&self) -> bool {
             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 @@ fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, fn_id: NodeId) {
         // 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 @@ fn is_label_valid_from_rib(&self, rib_index: usize) -> bool {
         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 @@ fn with_generic_param_rib<'c, F>(
         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 @@ fn with_generic_param_rib<'c, F>(
             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 @@ fn with_resolved_label(&mut self, label: Option<Label>, id: NodeId, f: impl FnOn
             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);
             });