1
Fork 0

Reuse resolve_label to check lifetime shadowing.

This commit is contained in:
Camille GILLOT 2022-06-02 20:35:14 +02:00
parent c75409d5e4
commit 86bd99060c
2 changed files with 29 additions and 40 deletions

View file

@ -1548,13 +1548,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
/// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved /// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved
/// label and reports an error if the label is not found or is unreachable. /// label and reports an error if the label is not found or is unreachable.
fn resolve_label(&mut self, mut label: Ident) -> Option<NodeId> { fn resolve_label(&mut self, mut label: Ident) -> Result<(NodeId, Span), ResolutionError<'a>> {
let mut suggestion = None; let mut suggestion = None;
// Preserve the original span so that errors contain "in this macro invocation"
// information.
let original_span = label.span;
for i in (0..self.label_ribs.len()).rev() { for i in (0..self.label_ribs.len()).rev() {
let rib = &self.label_ribs[i]; let rib = &self.label_ribs[i];
@ -1570,18 +1566,13 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
if let Some((ident, id)) = rib.bindings.get_key_value(&ident) { if let Some((ident, id)) = rib.bindings.get_key_value(&ident) {
let definition_span = ident.span; let definition_span = ident.span;
return if self.is_label_valid_from_rib(i) { return if self.is_label_valid_from_rib(i) {
Some(*id) Ok((*id, definition_span))
} else { } else {
self.report_error( Err(ResolutionError::UnreachableLabel {
original_span,
ResolutionError::UnreachableLabel {
name: label.name, name: label.name,
definition_span, definition_span,
suggestion, suggestion,
}, })
);
None
}; };
} }
@ -1590,11 +1581,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
suggestion = suggestion.or_else(|| self.suggestion_for_label_in_rib(i, label)); suggestion = suggestion.or_else(|| self.suggestion_for_label_in_rib(i, label));
} }
self.report_error( Err(ResolutionError::UndeclaredLabel { name: label.name, suggestion })
original_span,
ResolutionError::UndeclaredLabel { name: label.name, suggestion },
);
None
} }
/// Determine whether or not a label from the `rib_index`th label rib is reachable. /// Determine whether or not a label from the `rib_index`th label rib is reachable.
@ -3152,17 +3139,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
self.diagnostic_metadata.unused_labels.insert(id, label.ident.span); self.diagnostic_metadata.unused_labels.insert(id, label.ident.span);
} }
let ident = label.ident.normalize_to_macro_rules(); if let Ok((_, orig_span)) = self.resolve_label(label.ident) {
for rib in self.label_ribs.iter_mut().rev() { diagnostics::signal_label_shadowing(self.r.session, orig_span, label.ident)
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() {
break;
}
} }
self.with_label_rib(NormalRibKind, |this| { self.with_label_rib(NormalRibKind, |this| {
let ident = label.ident.normalize_to_macro_rules();
this.label_ribs.last_mut().unwrap().bindings.insert(ident, id); this.label_ribs.last_mut().unwrap().bindings.insert(ident, id);
f(this); f(this);
}); });
@ -3266,11 +3248,16 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
} }
ExprKind::Break(Some(label), _) | ExprKind::Continue(Some(label)) => { ExprKind::Break(Some(label), _) | ExprKind::Continue(Some(label)) => {
if let Some(node_id) = self.resolve_label(label.ident) { match self.resolve_label(label.ident) {
Ok((node_id, _)) => {
// Since this res is a label, it is never read. // Since this res is a label, it is never read.
self.r.label_res_map.insert(expr.id, node_id); self.r.label_res_map.insert(expr.id, node_id);
self.diagnostic_metadata.unused_labels.remove(&node_id); self.diagnostic_metadata.unused_labels.remove(&node_id);
} }
Err(error) => {
self.report_error(label.ident.span, error);
}
}
// visit `break` argument if any // visit `break` argument if any
visit::walk_expr(self, expr); visit::walk_expr(self, expr);

View file

@ -2066,15 +2066,17 @@ pub fn signal_lifetime_shadowing(
err.emit(); err.emit();
} }
/// Shadowing involving a label is only a warning, due to issues with /// Shadowing involving a label is only a warning for historical reasons.
/// labels and lifetimes not being macro-hygienic. //FIXME: make this a proper lint.
pub fn signal_label_shadowing(sess: &Session, orig: Ident, shadower: Ident) { pub fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) {
let name = shadower.name;
let shadower = shadower.span;
let mut err = sess.struct_span_warn( let mut err = sess.struct_span_warn(
shadower.span, shadower,
&format!("label name `{}` shadows a label name that is already in scope", orig.name), &format!("label name `{}` shadows a label name that is already in scope", name),
); );
err.span_label(orig.span, "first declared here"); err.span_label(orig, "first declared here");
err.span_label(shadower.span, format!("label `{}` already in scope", orig.name)); err.span_label(shadower, format!("label `{}` already in scope", name));
err.emit(); err.emit();
} }