Skip to content

Commit 3a90bed

Browse files
committed
Auto merge of #96296 - cjgillot:remove-label-lt-shadow, r=petrochenkov
Remove label/lifetime shadowing warnings This PR removes some pre-1.0 shadowing warnings for labels and lifetimes. The current behaviour of the compiler is to warn * labels that shadow unrelated labels in the same function --> removed ```rust 'a: loop {} 'a: loop {} // STOP WARNING ``` * labels that shadow enclosing labels --> kept, but only if shadowing is hygienic ```rust 'a: loop { 'a: loop {} // KEEP WARNING } ``` * labels that shadow lifetime --> removed ```rust fn foo<'a>() { 'a: loop {} // STOP WARNING } ``` * lifetimes that shadow labels --> removed ```rust 'a: loop { let b = Box::new(|x: &i8| *x) as Box<dyn for <'a> Fn(&'a i8) -> i8>; // STOP WARNING } ``` * lifetimes that shadow lifetimes --> kept ```rust fn foo<'a>() { let b = Box::new(|x: &i8| *x) as Box<dyn for <'a> Fn(&'a i8) -> i8>; // KEEP WARNING } ``` Closes #31745. ----- From `@petrochenkov` in #95781 (comment) > I think we should remove these silly checks entirely. > They were introduced long time ago in case some new language features appear and require this space. > Now we have another mechanism for such language changes - editions, and if "lifetimes in expressions" or something like that needs to be introduced it could be introduced as an edition change. > However, there was no plans to introduce anything like for years, so it's unlikely that even the edition mechanism will be necessary. r? rust-lang/lang
2 parents f5507aa + 2aa9c70 commit 3a90bed

31 files changed

+223
-1751
lines changed

compiler/rustc_ast_lowering/src/lib.rs

+9-12
Original file line numberDiff line numberDiff line change
@@ -1848,14 +1848,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
18481848
fn lower_generic_param(&mut self, param: &GenericParam) -> hir::GenericParam<'hir> {
18491849
let (name, kind) = match param.kind {
18501850
GenericParamKind::Lifetime => {
1851-
let param_name = if param.ident.name == kw::StaticLifetime
1852-
|| param.ident.name == kw::UnderscoreLifetime
1853-
{
1854-
ParamName::Error
1855-
} else {
1856-
let ident = self.lower_ident(param.ident);
1857-
ParamName::Plain(ident)
1858-
};
1851+
// AST resolution emitted an error on those parameters, so we lower them using
1852+
// `ParamName::Error`.
1853+
let param_name =
1854+
if let Some(LifetimeRes::Error) = self.resolver.get_lifetime_res(param.id) {
1855+
ParamName::Error
1856+
} else {
1857+
let ident = self.lower_ident(param.ident);
1858+
ParamName::Plain(ident)
1859+
};
18591860
let kind =
18601861
hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit };
18611862

@@ -1880,10 +1881,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
18801881
)
18811882
}
18821883
};
1883-
let name = match name {
1884-
hir::ParamName::Plain(ident) => hir::ParamName::Plain(self.lower_ident(ident)),
1885-
name => name,
1886-
};
18871884

18881885
let hir_id = self.lower_node_id(param.id);
18891886
self.lower_attrs(hir_id, &param.attrs);

compiler/rustc_error_codes/src/error_codes/E0263.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
#### Note: this error code is no longer emitted by the compiler.
2+
13
A lifetime was declared more than once in the same scope.
24

35
Erroneous code example:
46

5-
```compile_fail,E0263
7+
```compile_fail,E0403
68
fn foo<'a, 'b, 'a>(x: &'a str, y: &'b str, z: &'a str) { // error!
79
}
810
```

compiler/rustc_resolve/src/late.rs

+70-44
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,23 @@ impl RibKind<'_> {
172172
AssocItemRibKind | ItemRibKind(_) | ForwardGenericParamBanRibKind => true,
173173
}
174174
}
175+
176+
/// This rib forbids referring to labels defined in upwards ribs.
177+
fn is_label_barrier(self) -> bool {
178+
match self {
179+
NormalRibKind | MacroDefinition(..) => false,
180+
181+
AssocItemRibKind
182+
| ClosureOrAsyncRibKind
183+
| FnItemRibKind
184+
| ItemRibKind(..)
185+
| ConstantItemRibKind(..)
186+
| ModuleRibKind(..)
187+
| ForwardGenericParamBanRibKind
188+
| ConstParamTyRibKind
189+
| InlineAsmSymRibKind => true,
190+
}
191+
}
175192
}
176193

177194
/// A single local scope.
@@ -732,7 +749,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
732749
// Create a value rib for the function.
733750
self.with_rib(ValueNS, rib_kind, |this| {
734751
// Create a label rib for the function.
735-
this.with_label_rib(rib_kind, |this| {
752+
this.with_label_rib(FnItemRibKind, |this| {
736753
let async_node_id = fn_kind.header().and_then(|h| h.asyncness.opt_return_id());
737754

738755
if let FnKind::Fn(_, _, _, _, generics, _) = fn_kind {
@@ -1531,13 +1548,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
15311548

15321549
/// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved
15331550
/// label and reports an error if the label is not found or is unreachable.
1534-
fn resolve_label(&mut self, mut label: Ident) -> Option<NodeId> {
1551+
fn resolve_label(&mut self, mut label: Ident) -> Result<(NodeId, Span), ResolutionError<'a>> {
15351552
let mut suggestion = None;
15361553

1537-
// Preserve the original span so that errors contain "in this macro invocation"
1538-
// information.
1539-
let original_span = label.span;
1540-
15411554
for i in (0..self.label_ribs.len()).rev() {
15421555
let rib = &self.label_ribs[i];
15431556

@@ -1553,18 +1566,13 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
15531566
if let Some((ident, id)) = rib.bindings.get_key_value(&ident) {
15541567
let definition_span = ident.span;
15551568
return if self.is_label_valid_from_rib(i) {
1556-
Some(*id)
1569+
Ok((*id, definition_span))
15571570
} else {
1558-
self.report_error(
1559-
original_span,
1560-
ResolutionError::UnreachableLabel {
1561-
name: label.name,
1562-
definition_span,
1563-
suggestion,
1564-
},
1565-
);
1566-
1567-
None
1571+
Err(ResolutionError::UnreachableLabel {
1572+
name: label.name,
1573+
definition_span,
1574+
suggestion,
1575+
})
15681576
};
15691577
}
15701578

@@ -1573,34 +1581,16 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
15731581
suggestion = suggestion.or_else(|| self.suggestion_for_label_in_rib(i, label));
15741582
}
15751583

1576-
self.report_error(
1577-
original_span,
1578-
ResolutionError::UndeclaredLabel { name: label.name, suggestion },
1579-
);
1580-
None
1584+
Err(ResolutionError::UndeclaredLabel { name: label.name, suggestion })
15811585
}
15821586

15831587
/// Determine whether or not a label from the `rib_index`th label rib is reachable.
15841588
fn is_label_valid_from_rib(&self, rib_index: usize) -> bool {
15851589
let ribs = &self.label_ribs[rib_index + 1..];
15861590

15871591
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-
}
1592+
if rib.kind.is_label_barrier() {
1593+
return false;
16041594
}
16051595
}
16061596

@@ -1895,6 +1885,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
18951885
let mut function_value_rib = Rib::new(kind);
18961886
let mut function_lifetime_rib = LifetimeRib::new(lifetime_kind);
18971887
let mut seen_bindings = FxHashMap::default();
1888+
// Store all seen lifetimes names from outer scopes.
1889+
let mut seen_lifetimes = FxHashSet::default();
18981890

18991891
// We also can't shadow bindings from the parent item
19001892
if let AssocItemRibKind = kind {
@@ -1910,16 +1902,36 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
19101902
add_bindings_for_ns(TypeNS);
19111903
}
19121904

1905+
// Forbid shadowing lifetime bindings
1906+
for rib in self.lifetime_ribs.iter().rev() {
1907+
seen_lifetimes.extend(rib.bindings.iter().map(|(ident, _)| *ident));
1908+
if let LifetimeRibKind::Item = rib.kind {
1909+
break;
1910+
}
1911+
}
1912+
19131913
for param in params {
19141914
let ident = param.ident.normalize_to_macros_2_0();
19151915
debug!("with_generic_param_rib: {}", param.id);
19161916

1917+
if let GenericParamKind::Lifetime = param.kind
1918+
&& let Some(&original) = seen_lifetimes.get(&ident)
1919+
{
1920+
diagnostics::signal_lifetime_shadowing(self.r.session, original, param.ident);
1921+
// Record lifetime res, so lowering knows there is something fishy.
1922+
self.record_lifetime_res(param.id, LifetimeRes::Error);
1923+
continue;
1924+
}
1925+
19171926
match seen_bindings.entry(ident) {
19181927
Entry::Occupied(entry) => {
19191928
let span = *entry.get();
19201929
let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, span);
1921-
if !matches!(param.kind, GenericParamKind::Lifetime) {
1922-
self.report_error(param.ident.span, err);
1930+
self.report_error(param.ident.span, err);
1931+
if let GenericParamKind::Lifetime = param.kind {
1932+
// Record lifetime res, so lowering knows there is something fishy.
1933+
self.record_lifetime_res(param.id, LifetimeRes::Error);
1934+
continue;
19231935
}
19241936
}
19251937
Entry::Vacant(entry) => {
@@ -1936,6 +1948,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
19361948
)
19371949
.span_label(param.ident.span, "`'_` is a reserved lifetime name")
19381950
.emit();
1951+
// Record lifetime res, so lowering knows there is something fishy.
1952+
self.record_lifetime_res(param.id, LifetimeRes::Error);
19391953
continue;
19401954
}
19411955

@@ -1949,6 +1963,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
19491963
)
19501964
.span_label(param.ident.span, "'static is a reserved lifetime name")
19511965
.emit();
1966+
// Record lifetime res, so lowering knows there is something fishy.
1967+
self.record_lifetime_res(param.id, LifetimeRes::Error);
19521968
continue;
19531969
}
19541970

@@ -3114,6 +3130,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
31143130
if label.ident.as_str().as_bytes()[1] != b'_' {
31153131
self.diagnostic_metadata.unused_labels.insert(id, label.ident.span);
31163132
}
3133+
3134+
if let Ok((_, orig_span)) = self.resolve_label(label.ident) {
3135+
diagnostics::signal_label_shadowing(self.r.session, orig_span, label.ident)
3136+
}
3137+
31173138
self.with_label_rib(NormalRibKind, |this| {
31183139
let ident = label.ident.normalize_to_macro_rules();
31193140
this.label_ribs.last_mut().unwrap().bindings.insert(ident, id);
@@ -3219,10 +3240,15 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
32193240
}
32203241

32213242
ExprKind::Break(Some(label), _) | ExprKind::Continue(Some(label)) => {
3222-
if let Some(node_id) = self.resolve_label(label.ident) {
3223-
// Since this res is a label, it is never read.
3224-
self.r.label_res_map.insert(expr.id, node_id);
3225-
self.diagnostic_metadata.unused_labels.remove(&node_id);
3243+
match self.resolve_label(label.ident) {
3244+
Ok((node_id, _)) => {
3245+
// Since this res is a label, it is never read.
3246+
self.r.label_res_map.insert(expr.id, node_id);
3247+
self.diagnostic_metadata.unused_labels.remove(&node_id);
3248+
}
3249+
Err(error) => {
3250+
self.report_error(label.ident.span, error);
3251+
}
32263252
}
32273253

32283254
// visit `break` argument if any

compiler/rustc_resolve/src/late/diagnostics.rs

+29
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,34 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
20362037
}
20372038
}
20382039

2040+
/// Report lifetime/lifetime shadowing as an error.
2041+
pub fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: Ident) {
2042+
let mut err = struct_span_err!(
2043+
sess,
2044+
shadower.span,
2045+
E0496,
2046+
"lifetime name `{}` shadows a lifetime name that is already in scope",
2047+
orig.name,
2048+
);
2049+
err.span_label(orig.span, "first declared here");
2050+
err.span_label(shadower.span, format!("lifetime `{}` already in scope", orig.name));
2051+
err.emit();
2052+
}
2053+
2054+
/// Shadowing involving a label is only a warning for historical reasons.
2055+
//FIXME: make this a proper lint.
2056+
pub fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) {
2057+
let name = shadower.name;
2058+
let shadower = shadower.span;
2059+
let mut err = sess.struct_span_warn(
2060+
shadower,
2061+
&format!("label name `{}` shadows a label name that is already in scope", name),
2062+
);
2063+
err.span_label(orig, "first declared here");
2064+
err.span_label(shadower, format!("label `{}` already in scope", name));
2065+
err.emit();
2066+
}
2067+
20392068
impl<'tcx> LifetimeContext<'_, 'tcx> {
20402069
pub(crate) fn report_missing_lifetime_specifiers(
20412070
&self,

0 commit comments

Comments
 (0)