Skip to content

Commit 6e1b010

Browse files
committed
Diagnose shadowing on AST.
1 parent 20976ba commit 6e1b010

File tree

3 files changed

+209
-325
lines changed

3 files changed

+209
-325
lines changed

compiler/rustc_resolve/src/late.rs

Lines changed: 93 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ use crate::{path_names_to_string, BindingError, Finalize, LexicalScopeBinding};
1212
use crate::{Module, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult};
1313
use crate::{ResolutionError, Resolver, Segment, UseError};
1414

15+
use diagnostics::{
16+
original_label, original_lifetime, original_lifetime_param, shadower_label, shadower_lifetime,
17+
};
18+
1519
use rustc_ast::ptr::P;
1620
use rustc_ast::visit::{self, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
1721
use rustc_ast::*;
@@ -172,6 +176,23 @@ impl RibKind<'_> {
172176
AssocItemRibKind | ItemRibKind(_) | ForwardGenericParamBanRibKind => true,
173177
}
174178
}
179+
180+
/// This rib forbids referring to labels defined in upwards ribs.
181+
fn is_label_barrier(self) -> bool {
182+
match self {
183+
NormalRibKind | MacroDefinition(..) => false,
184+
185+
AssocItemRibKind
186+
| ClosureOrAsyncRibKind
187+
| FnItemRibKind
188+
| ItemRibKind(..)
189+
| ConstantItemRibKind(..)
190+
| ModuleRibKind(..)
191+
| ForwardGenericParamBanRibKind
192+
| ConstParamTyRibKind
193+
| InlineAsmSymRibKind => true,
194+
}
195+
}
175196
}
176197

177198
/// A single local scope.
@@ -732,7 +753,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
732753
// Create a value rib for the function.
733754
self.with_rib(ValueNS, rib_kind, |this| {
734755
// Create a label rib for the function.
735-
this.with_label_rib(rib_kind, |this| {
756+
this.with_label_rib(FnItemRibKind, |this| {
736757
let async_node_id = fn_kind.header().and_then(|h| h.asyncness.opt_return_id());
737758

738759
if let FnKind::Fn(_, _, _, _, generics, _) = fn_kind {
@@ -1585,22 +1606,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
15851606
let ribs = &self.label_ribs[rib_index + 1..];
15861607

15871608
for rib in ribs {
1588-
match rib.kind {
1589-
NormalRibKind | MacroDefinition(..) => {
1590-
// Nothing to do. Continue.
1591-
}
1592-
1593-
AssocItemRibKind
1594-
| ClosureOrAsyncRibKind
1595-
| FnItemRibKind
1596-
| ItemRibKind(..)
1597-
| ConstantItemRibKind(..)
1598-
| ModuleRibKind(..)
1599-
| ForwardGenericParamBanRibKind
1600-
| ConstParamTyRibKind
1601-
| InlineAsmSymRibKind => {
1602-
return false;
1603-
}
1609+
if rib.kind.is_label_barrier() {
1610+
return false;
16041611
}
16051612
}
16061613

@@ -1895,6 +1902,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
18951902
let mut function_value_rib = Rib::new(kind);
18961903
let mut function_lifetime_rib = LifetimeRib::new(lifetime_kind);
18971904
let mut seen_bindings = FxHashMap::default();
1905+
let mut seen_lifetimes = FxHashMap::default();
18981906

18991907
// We also can't shadow bindings from the parent item
19001908
if let AssocItemRibKind = kind {
@@ -1910,20 +1918,52 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
19101918
add_bindings_for_ns(TypeNS);
19111919
}
19121920

1921+
// Forbid shadowing lifetime bindings
1922+
for rib in self.lifetime_ribs.iter().rev() {
1923+
seen_lifetimes.extend(
1924+
rib.bindings.iter().map(|(ident, _)| (*ident, original_lifetime(ident.span))),
1925+
);
1926+
if let LifetimeRibKind::Item = rib.kind {
1927+
break;
1928+
}
1929+
}
1930+
for rib in self.label_ribs.iter().rev() {
1931+
if rib.kind.is_label_barrier() {
1932+
break;
1933+
}
1934+
seen_lifetimes
1935+
.extend(rib.bindings.iter().map(|(ident, _)| (*ident, original_label(ident.span))));
1936+
}
1937+
19131938
for param in params {
19141939
let ident = param.ident.normalize_to_macros_2_0();
19151940
debug!("with_generic_param_rib: {}", param.id);
19161941

1917-
match seen_bindings.entry(ident) {
1918-
Entry::Occupied(entry) => {
1919-
let span = *entry.get();
1920-
let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, span);
1921-
if !matches!(param.kind, GenericParamKind::Lifetime) {
1922-
self.report_error(param.ident.span, err);
1942+
if let GenericParamKind::Lifetime = param.kind {
1943+
match seen_lifetimes.entry(ident) {
1944+
Entry::Occupied(entry) => {
1945+
let original = *entry.get();
1946+
diagnostics::signal_shadowing_problem(
1947+
self.r.session,
1948+
ident.name,
1949+
original,
1950+
shadower_lifetime(param.ident.span),
1951+
)
1952+
}
1953+
Entry::Vacant(entry) => {
1954+
entry.insert(original_lifetime_param(param.ident.span));
19231955
}
19241956
}
1925-
Entry::Vacant(entry) => {
1926-
entry.insert(param.ident.span);
1957+
} else {
1958+
match seen_bindings.entry(ident) {
1959+
Entry::Occupied(entry) => {
1960+
let span = *entry.get();
1961+
let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, span);
1962+
self.report_error(param.ident.span, err);
1963+
}
1964+
Entry::Vacant(entry) => {
1965+
entry.insert(param.ident.span);
1966+
}
19271967
}
19281968
}
19291969

@@ -3114,8 +3154,35 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
31143154
if label.ident.as_str().as_bytes()[1] != b'_' {
31153155
self.diagnostic_metadata.unused_labels.insert(id, label.ident.span);
31163156
}
3157+
3158+
// Forbid shadowing lifetime bindings
3159+
let ident = label.ident.normalize_to_macro_rules();
3160+
for rib in self.lifetime_ribs.iter().rev() {
3161+
if let Some((orig_ident, _)) = rib.bindings.get_key_value(&ident) {
3162+
diagnostics::signal_shadowing_problem(
3163+
self.r.session,
3164+
label.ident.name,
3165+
original_lifetime(orig_ident.span),
3166+
shadower_label(label.ident.span),
3167+
)
3168+
}
3169+
}
3170+
for rib in self.label_ribs.iter_mut().rev() {
3171+
if let Some((orig_ident, _)) = rib.bindings.get_key_value(&ident) {
3172+
diagnostics::signal_shadowing_problem(
3173+
self.r.session,
3174+
label.ident.name,
3175+
original_label(orig_ident.span),
3176+
shadower_label(label.ident.span),
3177+
)
3178+
}
3179+
if rib.kind.is_label_barrier() {
3180+
rib.bindings.insert(ident, id);
3181+
break;
3182+
}
3183+
}
3184+
31173185
self.with_label_rib(NormalRibKind, |this| {
3118-
let ident = label.ident.normalize_to_macro_rules();
31193186
this.label_ribs.last_mut().unwrap().bindings.insert(ident, id);
31203187
f(this);
31213188
});

compiler/rustc_resolve/src/late/diagnostics.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
2525
use rustc_hir::PrimTy;
2626
use rustc_session::lint;
2727
use rustc_session::parse::feature_err;
28+
use rustc_session::Session;
2829
use rustc_span::edition::Edition;
2930
use rustc_span::hygiene::MacroKind;
3031
use rustc_span::lev_distance::find_best_match_for_name;
@@ -2036,6 +2037,87 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
20362037
}
20372038
}
20382039

2040+
#[derive(Copy, Clone, PartialEq)]
2041+
enum ShadowKind {
2042+
Label,
2043+
Lifetime,
2044+
}
2045+
#[derive(Copy, Clone)]
2046+
pub struct Original {
2047+
kind: ShadowKind,
2048+
span: Span,
2049+
param: bool,
2050+
}
2051+
#[derive(Copy, Clone)]
2052+
pub struct Shadower {
2053+
kind: ShadowKind,
2054+
span: Span,
2055+
}
2056+
2057+
pub fn original_label(span: Span) -> Original {
2058+
Original { kind: ShadowKind::Label, span, param: false }
2059+
}
2060+
pub fn shadower_label(span: Span) -> Shadower {
2061+
Shadower { kind: ShadowKind::Label, span }
2062+
}
2063+
pub fn original_lifetime(span: Span) -> Original {
2064+
Original { kind: ShadowKind::Lifetime, span, param: false }
2065+
}
2066+
pub fn original_lifetime_param(span: Span) -> Original {
2067+
Original { kind: ShadowKind::Lifetime, span, param: true }
2068+
}
2069+
pub fn shadower_lifetime(span: Span) -> Shadower {
2070+
Shadower { kind: ShadowKind::Lifetime, span }
2071+
}
2072+
2073+
impl ShadowKind {
2074+
fn desc(&self) -> &'static str {
2075+
match *self {
2076+
ShadowKind::Label => "label",
2077+
ShadowKind::Lifetime => "lifetime",
2078+
}
2079+
}
2080+
}
2081+
2082+
pub fn signal_shadowing_problem(sess: &Session, name: Symbol, orig: Original, shadower: Shadower) {
2083+
let mut err = if let (ShadowKind::Lifetime, ShadowKind::Lifetime) = (orig.kind, shadower.kind) {
2084+
// lifetime/lifetime shadowing is an error
2085+
if orig.param {
2086+
struct_span_err!(
2087+
sess,
2088+
shadower.span,
2089+
E0263,
2090+
"lifetime name `{}` declared twice in the same scope",
2091+
name,
2092+
)
2093+
} else {
2094+
struct_span_err!(
2095+
sess,
2096+
shadower.span,
2097+
E0496,
2098+
"lifetime name `{}` shadows a lifetime name that is already in scope",
2099+
name,
2100+
)
2101+
}
2102+
.forget_guarantee()
2103+
} else {
2104+
// shadowing involving a label is only a warning, due to issues with
2105+
// labels and lifetimes not being macro-hygienic.
2106+
sess.struct_span_warn(
2107+
shadower.span,
2108+
&format!(
2109+
"{} name `{}` shadows a {} name that is already in scope",
2110+
shadower.kind.desc(),
2111+
name,
2112+
orig.kind.desc()
2113+
),
2114+
)
2115+
};
2116+
err.span_label(orig.span, "first declared here");
2117+
err.span_label(shadower.span, format!("{} `{}` already in scope", orig.kind.desc(), name));
2118+
err.emit();
2119+
}
2120+
20392121
impl<'tcx> LifetimeContext<'_, 'tcx> {
20402122
pub(crate) fn report_missing_lifetime_specifiers(
20412123
&self,

0 commit comments

Comments
 (0)