diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index a5527158aab3c..00c072e1b04a1 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -448,6 +448,7 @@ E0763: include_str!("./error_codes/E0763.md"), E0764: include_str!("./error_codes/E0764.md"), E0765: include_str!("./error_codes/E0765.md"), E0766: include_str!("./error_codes/E0766.md"), +E0767: include_str!("./error_codes/E0767.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard diff --git a/src/librustc_error_codes/error_codes/E0767.md b/src/librustc_error_codes/error_codes/E0767.md new file mode 100644 index 0000000000000..679fe7e41e9c7 --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0767.md @@ -0,0 +1,20 @@ +An unreachable label was used. + +Erroneous code example: + +```compile_fail,E0767 +'a: loop { + || { + loop { break 'a } // error: use of unreachable label `'a` + }; +} +``` + +Ensure that the label is within scope. Labels are not reachable through +functions, closures, async blocks or modules. Example: + +``` +'a: loop { + break 'a; // ok! +} +``` diff --git a/src/librustc_passes/liveness.rs b/src/librustc_passes/liveness.rs index 798c6b8925bbf..b288a41e0cfd6 100644 --- a/src/librustc_passes/liveness.rs +++ b/src/librustc_passes/liveness.rs @@ -1123,16 +1123,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { match target { Some(b) => self.propagate_through_opt_expr(opt_expr.as_ref().map(|e| &**e), b), - None => { - // FIXME: This should have been checked earlier. Once this is fixed, - // replace with `delay_span_bug`. (#62480) - self.ir - .tcx - .sess - .struct_span_err(expr.span, "`break` to unknown label") - .emit(); - rustc_errors::FatalError.raise() - } + None => span_bug!(expr.span, "`break` to unknown label"), } } diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 2854683b61bab..c64c617b54b59 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -33,6 +33,10 @@ type Res = def::Res; /// A vector of spans and replacements, a message and applicability. crate type Suggestion = (Vec<(Span, String)>, String, Applicability); +/// Potential candidate for an undeclared or out-of-scope label - contains the ident of a +/// similarly named label and whether or not it is reachable. +crate type LabelSuggestion = (Ident, bool); + crate struct TypoSuggestion { pub candidate: Symbol, pub res: Res, @@ -282,7 +286,7 @@ impl<'a> Resolver<'a> { err.span_label(span, "used in a pattern more than once"); err } - ResolutionError::UndeclaredLabel(name, lev_candidate) => { + ResolutionError::UndeclaredLabel { name, suggestion } => { let mut err = struct_span_err!( self.session, span, @@ -290,16 +294,31 @@ impl<'a> Resolver<'a> { "use of undeclared label `{}`", name ); - if let Some(lev_candidate) = lev_candidate { - err.span_suggestion( - span, - "a label with a similar name exists in this scope", - lev_candidate.to_string(), - Applicability::MaybeIncorrect, - ); - } else { - err.span_label(span, format!("undeclared label `{}`", name)); + + err.span_label(span, format!("undeclared label `{}`", name)); + + match suggestion { + // A reachable label with a similar name exists. + Some((ident, true)) => { + err.span_label(ident.span, "a label with a similar name is reachable"); + err.span_suggestion( + span, + "try using similarly named label", + ident.name.to_string(), + Applicability::MaybeIncorrect, + ); + } + // An unreachable label with a similar name exists. + Some((ident, false)) => { + err.span_label( + ident.span, + "a label with a similar name exists but is unreachable", + ); + } + // No similarly-named labels exist. + None => (), } + err } ResolutionError::SelfImportsOnlyAllowedWithin { root, span_with_rename } => { @@ -433,6 +452,45 @@ impl<'a> Resolver<'a> { err.span_label(span, "`Self` in type parameter default".to_string()); err } + ResolutionError::UnreachableLabel { name, definition_span, suggestion } => { + let mut err = struct_span_err!( + self.session, + span, + E0767, + "use of unreachable label `{}`", + name, + ); + + err.span_label(definition_span, "unreachable label defined here"); + err.span_label(span, format!("unreachable label `{}`", name)); + err.note( + "labels are unreachable through functions, closures, async blocks and modules", + ); + + match suggestion { + // A reachable label with a similar name exists. + Some((ident, true)) => { + err.span_label(ident.span, "a label with a similar name is reachable"); + err.span_suggestion( + span, + "try using similarly named label", + ident.name.to_string(), + Applicability::MaybeIncorrect, + ); + } + // An unreachable label with a similar name exists. + Some((ident, false)) => { + err.span_label( + ident.span, + "a label with a similar name exists but is also unreachable", + ); + } + // No similarly-named labels exist. + None => (), + } + + err + } } } diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 84ba9094ea16f..4451791780ead 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -13,7 +13,6 @@ use crate::{ResolutionError, Resolver, Segment, UseError}; use rustc_ast::ast::*; use rustc_ast::ptr::P; -use rustc_ast::util::lev_distance::find_best_match_for_name; use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use rustc_ast::{unwrap_or, walk_list}; use rustc_ast_lowering::ResolverAstLowering; @@ -101,6 +100,9 @@ crate enum RibKind<'a> { /// upvars). AssocItemRibKind, + /// We passed through a closure. Disallow labels. + ClosureOrAsyncRibKind, + /// We passed through a function definition. Disallow upvars. /// Permit only those const parameters that are specified in the function's generics. FnItemRibKind, @@ -124,11 +126,15 @@ crate enum RibKind<'a> { } impl RibKind<'_> { - // Whether this rib kind contains generic parameters, as opposed to local - // variables. + /// Whether this rib kind contains generic parameters, as opposed to local + /// variables. crate fn contains_params(&self) -> bool { match self { - NormalRibKind | FnItemRibKind | ConstantItemRibKind | ModuleRibKind(_) + NormalRibKind + | ClosureOrAsyncRibKind + | FnItemRibKind + | ConstantItemRibKind + | ModuleRibKind(_) | MacroDefinition(_) => false, AssocItemRibKind | ItemRibKind(_) | ForwardTyParamBanRibKind => true, } @@ -474,7 +480,8 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { // Bail if there's no body. FnKind::Fn(.., None) => return visit::walk_fn(self, fn_kind, sp), FnKind::Fn(FnCtxt::Free | FnCtxt::Foreign, ..) => FnItemRibKind, - FnKind::Fn(FnCtxt::Assoc(_), ..) | FnKind::Closure(..) => NormalRibKind, + FnKind::Fn(FnCtxt::Assoc(_), ..) => NormalRibKind, + FnKind::Closure(..) => ClosureOrAsyncRibKind, }; let previous_value = replace(&mut self.diagnostic_metadata.current_function, Some((fn_kind, sp))); @@ -725,37 +732,81 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } } - /// Searches the current set of local scopes for labels. Returns the first non-`None` label that - /// is returned by the given predicate function - /// - /// Stops after meeting a closure. - fn search_label(&self, mut ident: Ident, pred: P) -> Option - where - P: Fn(&Rib<'_, NodeId>, Ident) -> Option, - { - for rib in self.label_ribs.iter().rev() { - match rib.kind { - NormalRibKind => {} + /// 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. + fn resolve_label(&self, mut label: Ident) -> Option { + 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() { + let rib = &self.label_ribs[i]; + + if let MacroDefinition(def) = rib.kind { // If an invocation of this macro created `ident`, give up on `ident` // and switch to `ident`'s source from the macro definition. - MacroDefinition(def) => { - if def == self.r.macro_def(ident.span.ctxt()) { - ident.span.remove_mark(); - } - } - _ => { - // Do not resolve labels across function boundary - return None; + if def == self.r.macro_def(label.span.ctxt()) { + label.span.remove_mark(); } } - let r = pred(rib, ident); - if r.is_some() { - return r; + + let ident = label.normalize_to_macro_rules(); + if let Some((ident, id)) = rib.bindings.get_key_value(&ident) { + return if self.is_label_valid_from_rib(i) { + Some(*id) + } else { + self.r.report_error( + original_span, + ResolutionError::UnreachableLabel { + name: &label.name.as_str(), + definition_span: ident.span, + suggestion, + }, + ); + + None + }; } + + // Diagnostics: Check if this rib contains a label with a similar name, keep track of + // the first such label that is encountered. + suggestion = suggestion.or_else(|| self.suggestion_for_label_in_rib(i, label)); } + + self.r.report_error( + original_span, + ResolutionError::UndeclaredLabel { name: &label.name.as_str(), suggestion }, + ); None } + /// Determine whether or not a label from the `rib_index`th label rib is reachable. + 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(..) + | ForwardTyParamBanRibKind => { + return false; + } + } + } + + true + } + fn resolve_adt(&mut self, item: &'ast Item, generics: &'ast Generics) { debug!("resolve_adt"); self.with_current_self_item(item, |this| { @@ -2044,35 +2095,10 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } ExprKind::Break(Some(label), _) | ExprKind::Continue(Some(label)) => { - let node_id = self.search_label(label.ident, |rib, ident| { - rib.bindings.get(&ident.normalize_to_macro_rules()).cloned() - }); - match node_id { - None => { - // Search again for close matches... - // Picks the first label that is "close enough", which is not necessarily - // the closest match - let close_match = self.search_label(label.ident, |rib, ident| { - let names = rib.bindings.iter().filter_map(|(id, _)| { - if id.span.ctxt() == label.ident.span.ctxt() { - Some(&id.name) - } else { - None - } - }); - find_best_match_for_name(names, &ident.as_str(), None) - }); - self.r.record_partial_res(expr.id, PartialRes::new(Res::Err)); - self.r.report_error( - label.ident.span, - ResolutionError::UndeclaredLabel(&label.ident.as_str(), close_match), - ); - } - Some(node_id) => { - // Since this res is a label, it is never read. - self.r.label_res_map.insert(expr.id, node_id); - self.diagnostic_metadata.unused_labels.remove(&node_id); - } + if let Some(node_id) = self.resolve_label(label.ident) { + // Since this res is a label, it is never read. + self.r.label_res_map.insert(expr.id, node_id); + self.diagnostic_metadata.unused_labels.remove(&node_id); } // visit `break` argument if any @@ -2144,21 +2170,26 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // closure are detected as upvars rather than normal closure arg usages. ExprKind::Closure(_, Async::Yes { .. }, _, ref fn_decl, ref body, _span) => { self.with_rib(ValueNS, NormalRibKind, |this| { - // Resolve arguments: - this.resolve_params(&fn_decl.inputs); - // No need to resolve return type -- - // the outer closure return type is `FnRetTy::Default`. + this.with_label_rib(ClosureOrAsyncRibKind, |this| { + // Resolve arguments: + this.resolve_params(&fn_decl.inputs); + // No need to resolve return type -- + // the outer closure return type is `FnRetTy::Default`. - // Now resolve the inner closure - { - // No need to resolve arguments: the inner closure has none. - // Resolve the return type: - visit::walk_fn_ret_ty(this, &fn_decl.output); - // Resolve the body - this.visit_expr(body); - } + // Now resolve the inner closure + { + // No need to resolve arguments: the inner closure has none. + // Resolve the return type: + visit::walk_fn_ret_ty(this, &fn_decl.output); + // Resolve the body + this.visit_expr(body); + } + }) }); } + ExprKind::Async(..) | ExprKind::Closure(..) => { + self.with_label_rib(ClosureOrAsyncRibKind, |this| visit::walk_expr(this, expr)); + } _ => { visit::walk_expr(self, expr); } diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs index 1bce160acb610..e469ca80c590a 100644 --- a/src/librustc_resolve/late/diagnostics.rs +++ b/src/librustc_resolve/late/diagnostics.rs @@ -1,4 +1,4 @@ -use crate::diagnostics::{ImportSuggestion, TypoSuggestion}; +use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion}; use crate::late::lifetimes::{ElisionFailureInfo, LifetimeContext}; use crate::late::{LateResolutionVisitor, RibKind}; use crate::path_names_to_string; @@ -992,6 +992,32 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { } None } + + /// Given the target `label`, search the `rib_index`th label rib for similarly named labels, + /// optionally returning the closest match and whether it is reachable. + crate fn suggestion_for_label_in_rib( + &self, + rib_index: usize, + label: Ident, + ) -> Option { + // Are ribs from this `rib_index` within scope? + let within_scope = self.is_label_valid_from_rib(rib_index); + + let rib = &self.label_ribs[rib_index]; + let names = rib + .bindings + .iter() + .filter(|(id, _)| id.span.ctxt() == label.span.ctxt()) + .map(|(id, _)| &id.name); + + find_best_match_for_name(names, &label.as_str(), None).map(|symbol| { + // Upon finding a similar name, get the ident that it was from - the span + // contained within helps make a useful diagnostic. In addition, determine + // whether this candidate is within scope. + let (ident, _) = rib.bindings.iter().find(|(ident, _)| ident.name == symbol).unwrap(); + (*ident, within_scope) + }) + } } impl<'tcx> LifetimeContext<'_, 'tcx> { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index dccaf76723a58..f3a1934abc9fe 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -61,7 +61,7 @@ use std::collections::BTreeSet; use std::{cmp, fmt, iter, ptr}; use diagnostics::{extend_span_to_previous_binding, find_span_of_binding_until_next_binding}; -use diagnostics::{ImportSuggestion, Suggestion}; +use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion}; use imports::{Import, ImportKind, ImportResolver, NameResolution}; use late::{HasGenericParams, PathSource, Rib, RibKind::*}; use macros::{MacroRulesBinding, MacroRulesScope}; @@ -197,7 +197,7 @@ enum ResolutionError<'a> { /// Error E0416: identifier is bound more than once in the same pattern. IdentifierBoundMoreThanOnceInSamePattern(&'a str), /// Error E0426: use of undeclared label. - UndeclaredLabel(&'a str, Option), + UndeclaredLabel { name: &'a str, suggestion: Option }, /// Error E0429: `self` imports are only allowed within a `{ }` list. SelfImportsOnlyAllowedWithin { root: bool, span_with_rename: Span }, /// Error E0430: `self` import can only appear once in the list. @@ -216,6 +216,8 @@ enum ResolutionError<'a> { ForwardDeclaredTyParam, // FIXME(const_generics:defaults) /// Error E0735: type parameters with a default cannot use `Self` SelfInTyParamDefault, + /// Error E0767: use of unreachable label + UnreachableLabel { name: &'a str, definition_span: Span, suggestion: Option }, } enum VisResolutionError<'a> { @@ -2453,6 +2455,7 @@ impl<'a> Resolver<'a> { for rib in ribs { match rib.kind { NormalRibKind + | ClosureOrAsyncRibKind | ModuleRibKind(..) | MacroDefinition(..) | ForwardTyParamBanRibKind => { @@ -2488,6 +2491,7 @@ impl<'a> Resolver<'a> { for rib in ribs { let has_generic_params = match rib.kind { NormalRibKind + | ClosureOrAsyncRibKind | AssocItemRibKind | ModuleRibKind(..) | MacroDefinition(..) diff --git a/src/test/ui/break-outside-loop.rs b/src/test/ui/break-outside-loop.rs index a6f9d0423d082..26769b30dd5f0 100644 --- a/src/test/ui/break-outside-loop.rs +++ b/src/test/ui/break-outside-loop.rs @@ -27,7 +27,9 @@ fn main() { // not the `loop`, which failed in the call to `find_breakable`. (#65383) 'lab: loop { || { - break 'lab; //~ ERROR `break` inside of a closure + break 'lab; + //~^ ERROR use of unreachable label `'lab` + //~| ERROR `break` inside of a closure }; } } diff --git a/src/test/ui/break-outside-loop.stderr b/src/test/ui/break-outside-loop.stderr index 8e300fd848dab..287bf9af62e49 100644 --- a/src/test/ui/break-outside-loop.stderr +++ b/src/test/ui/break-outside-loop.stderr @@ -1,3 +1,14 @@ +error[E0767]: use of unreachable label `'lab` + --> $DIR/break-outside-loop.rs:30:19 + | +LL | 'lab: loop { + | ---- unreachable label defined here +LL | || { +LL | break 'lab; + | ^^^^ unreachable label `'lab` + | + = note: labels are unreachable through functions, closures, async blocks and modules + error[E0268]: `break` outside of a loop --> $DIR/break-outside-loop.rs:10:15 | @@ -41,7 +52,7 @@ LL | || { LL | break 'lab; | ^^^^^^^^^^ cannot `break` inside of a closure -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors -Some errors have detailed explanations: E0267, E0268. +Some errors have detailed explanations: E0267, E0268, E0767. For more information about an error, try `rustc --explain E0267`. diff --git a/src/test/ui/error-codes/E0767.rs b/src/test/ui/error-codes/E0767.rs new file mode 100644 index 0000000000000..6c6cb746e6c75 --- /dev/null +++ b/src/test/ui/error-codes/E0767.rs @@ -0,0 +1,7 @@ +fn main () { + 'a: loop { + || { + loop { break 'a; } //~ ERROR E0767 + } + } +} diff --git a/src/test/ui/error-codes/E0767.stderr b/src/test/ui/error-codes/E0767.stderr new file mode 100644 index 0000000000000..2429823306b6e --- /dev/null +++ b/src/test/ui/error-codes/E0767.stderr @@ -0,0 +1,14 @@ +error[E0767]: use of unreachable label `'a` + --> $DIR/E0767.rs:4:26 + | +LL | 'a: loop { + | -- unreachable label defined here +LL | || { +LL | loop { break 'a; } + | ^^ unreachable label `'a` + | + = note: labels are unreachable through functions, closures, async blocks and modules + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0767`. diff --git a/src/test/ui/issues/issue-62480.rs b/src/test/ui/issues/issue-62480.rs index bc3e6c69a6024..5c3be3e64ee1a 100644 --- a/src/test/ui/issues/issue-62480.rs +++ b/src/test/ui/issues/issue-62480.rs @@ -5,6 +5,8 @@ fn main() { // `propagate_through_expr` would be the closure and not the `loop`, which wouldn't be found in // `self.break_ln`. (#62480) 'a: { - || break 'a //~ ERROR `break` to unknown label + || break 'a + //~^ ERROR use of unreachable label `'a` + //~| ERROR `break` inside of a closure } } diff --git a/src/test/ui/issues/issue-62480.stderr b/src/test/ui/issues/issue-62480.stderr index de8451ad7df0a..17085ef908bdf 100644 --- a/src/test/ui/issues/issue-62480.stderr +++ b/src/test/ui/issues/issue-62480.stderr @@ -1,8 +1,22 @@ -error: `break` to unknown label +error[E0767]: use of unreachable label `'a` + --> $DIR/issue-62480.rs:8:18 + | +LL | 'a: { + | -- unreachable label defined here +LL | || break 'a + | ^^ unreachable label `'a` + | + = note: labels are unreachable through functions, closures, async blocks and modules + +error[E0267]: `break` inside of a closure --> $DIR/issue-62480.rs:8:12 | LL | || break 'a - | ^^^^^^^^ + | -- ^^^^^^^^ cannot `break` inside of a closure + | | + | enclosing closure -error: aborting due to previous error +error: aborting due to 2 previous errors +Some errors have detailed explanations: E0267, E0767. +For more information about an error, try `rustc --explain E0267`. diff --git a/src/test/ui/issues/issue-66702-break-outside-loop-val.rs b/src/test/ui/issues/issue-66702-break-outside-loop-val.rs index bd3c00d262128..05b86cbbf8f05 100644 --- a/src/test/ui/issues/issue-66702-break-outside-loop-val.rs +++ b/src/test/ui/issues/issue-66702-break-outside-loop-val.rs @@ -2,6 +2,8 @@ fn main() { 'some_label: loop { - || break 'some_label (); //~ ERROR: `break` inside of a closure + || break 'some_label (); + //~^ ERROR: use of unreachable label `'some_label` + //~| ERROR: `break` inside of a closure } } diff --git a/src/test/ui/issues/issue-66702-break-outside-loop-val.stderr b/src/test/ui/issues/issue-66702-break-outside-loop-val.stderr index 83bde9775b2ec..f92ede311afb4 100644 --- a/src/test/ui/issues/issue-66702-break-outside-loop-val.stderr +++ b/src/test/ui/issues/issue-66702-break-outside-loop-val.stderr @@ -1,3 +1,13 @@ +error[E0767]: use of unreachable label `'some_label` + --> $DIR/issue-66702-break-outside-loop-val.rs:5:18 + | +LL | 'some_label: loop { + | ----------- unreachable label defined here +LL | || break 'some_label (); + | ^^^^^^^^^^^ unreachable label `'some_label` + | + = note: labels are unreachable through functions, closures, async blocks and modules + error[E0267]: `break` inside of a closure --> $DIR/issue-66702-break-outside-loop-val.rs:5:12 | @@ -6,6 +16,7 @@ LL | || break 'some_label (); | | | enclosing closure -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0267`. +Some errors have detailed explanations: E0267, E0767. +For more information about an error, try `rustc --explain E0267`. diff --git a/src/test/ui/issues/issue-73541-1.rs b/src/test/ui/issues/issue-73541-1.rs new file mode 100644 index 0000000000000..7fb0d6c39ff6b --- /dev/null +++ b/src/test/ui/issues/issue-73541-1.rs @@ -0,0 +1,12 @@ +// edition:2018 + +fn main() { + 'a: loop { + async { + loop { + continue 'a + //~^ ERROR use of unreachable label `'a` + } + }; + } +} diff --git a/src/test/ui/issues/issue-73541-1.stderr b/src/test/ui/issues/issue-73541-1.stderr new file mode 100644 index 0000000000000..80c1fdf002a83 --- /dev/null +++ b/src/test/ui/issues/issue-73541-1.stderr @@ -0,0 +1,14 @@ +error[E0767]: use of unreachable label `'a` + --> $DIR/issue-73541-1.rs:7:26 + | +LL | 'a: loop { + | -- unreachable label defined here +... +LL | continue 'a + | ^^ unreachable label `'a` + | + = note: labels are unreachable through functions, closures, async blocks and modules + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0767`. diff --git a/src/test/ui/issues/issue-73541-2.rs b/src/test/ui/issues/issue-73541-2.rs new file mode 100644 index 0000000000000..70b4ab2537626 --- /dev/null +++ b/src/test/ui/issues/issue-73541-2.rs @@ -0,0 +1,20 @@ +// edition:2018 + +async fn c() { + 'a: loop { + macro_rules! b { + () => { + continue 'a + //~^ ERROR use of unreachable label `'a` + } + } + + async { + loop { + b!(); + } + }; + } +} + +fn main() { } diff --git a/src/test/ui/issues/issue-73541-2.stderr b/src/test/ui/issues/issue-73541-2.stderr new file mode 100644 index 0000000000000..75d769c4e1545 --- /dev/null +++ b/src/test/ui/issues/issue-73541-2.stderr @@ -0,0 +1,18 @@ +error[E0767]: use of unreachable label `'a` + --> $DIR/issue-73541-2.rs:7:26 + | +LL | 'a: loop { + | -- unreachable label defined here +... +LL | continue 'a + | ^^ unreachable label `'a` +... +LL | b!(); + | ----- in this macro invocation + | + = note: labels are unreachable through functions, closures, async blocks and modules + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0767`. diff --git a/src/test/ui/issues/issue-73541-3.rs b/src/test/ui/issues/issue-73541-3.rs new file mode 100644 index 0000000000000..02ca02da8ed61 --- /dev/null +++ b/src/test/ui/issues/issue-73541-3.rs @@ -0,0 +1,9 @@ +fn main() { + 'aaaaab: loop { + || { + loop { continue 'aaaaaa } + //~^ ERROR use of undeclared label `'aaaaaa` + }; + + } +} diff --git a/src/test/ui/issues/issue-73541-3.stderr b/src/test/ui/issues/issue-73541-3.stderr new file mode 100644 index 0000000000000..53487aaca998c --- /dev/null +++ b/src/test/ui/issues/issue-73541-3.stderr @@ -0,0 +1,12 @@ +error[E0426]: use of undeclared label `'aaaaaa` + --> $DIR/issue-73541-3.rs:4:29 + | +LL | 'aaaaab: loop { + | ------- a label with a similar name exists but is unreachable +LL | || { +LL | loop { continue 'aaaaaa } + | ^^^^^^^ undeclared label `'aaaaaa` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0426`. diff --git a/src/test/ui/issues/issue-73541.rs b/src/test/ui/issues/issue-73541.rs new file mode 100644 index 0000000000000..399a07cd3fcc8 --- /dev/null +++ b/src/test/ui/issues/issue-73541.rs @@ -0,0 +1,9 @@ +fn main() { + 'a: loop { + || { + loop { continue 'a } + //~^ ERROR use of unreachable label `'a` + }; + + } +} diff --git a/src/test/ui/issues/issue-73541.stderr b/src/test/ui/issues/issue-73541.stderr new file mode 100644 index 0000000000000..4bb466ff16c58 --- /dev/null +++ b/src/test/ui/issues/issue-73541.stderr @@ -0,0 +1,14 @@ +error[E0767]: use of unreachable label `'a` + --> $DIR/issue-73541.rs:4:29 + | +LL | 'a: loop { + | -- unreachable label defined here +LL | || { +LL | loop { continue 'a } + | ^^ unreachable label `'a` + | + = note: labels are unreachable through functions, closures, async blocks and modules + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0767`. diff --git a/src/test/ui/resolve/resolve-label.rs b/src/test/ui/resolve/resolve-label.rs index 965ee4501044b..ac5410cd35522 100644 --- a/src/test/ui/resolve/resolve-label.rs +++ b/src/test/ui/resolve/resolve-label.rs @@ -2,7 +2,7 @@ fn f() { 'l: loop { fn g() { loop { - break 'l; //~ ERROR use of undeclared label + break 'l; //~ ERROR use of unreachable label } } } diff --git a/src/test/ui/resolve/resolve-label.stderr b/src/test/ui/resolve/resolve-label.stderr index 72a8e443bac9f..5729348ef2104 100644 --- a/src/test/ui/resolve/resolve-label.stderr +++ b/src/test/ui/resolve/resolve-label.stderr @@ -1,9 +1,14 @@ -error[E0426]: use of undeclared label `'l` +error[E0767]: use of unreachable label `'l` --> $DIR/resolve-label.rs:5:23 | +LL | 'l: loop { + | -- unreachable label defined here +... LL | break 'l; - | ^^ undeclared label `'l` + | ^^ unreachable label `'l` + | + = note: labels are unreachable through functions, closures, async blocks and modules error: aborting due to previous error -For more information about this error, try `rustc --explain E0426`. +For more information about this error, try `rustc --explain E0767`. diff --git a/src/test/ui/suggestions/suggest-labels.stderr b/src/test/ui/suggestions/suggest-labels.stderr index 079821e649070..aac6515b527c7 100644 --- a/src/test/ui/suggestions/suggest-labels.stderr +++ b/src/test/ui/suggestions/suggest-labels.stderr @@ -1,35 +1,35 @@ error[E0426]: use of undeclared label `'fo` --> $DIR/suggest-labels.rs:4:15 | +LL | 'foo: loop { + | ---- a label with a similar name is reachable LL | break 'fo; | ^^^ - | -help: a label with a similar name exists in this scope - | -LL | break 'foo; - | ^^^^ + | | + | undeclared label `'fo` + | help: try using similarly named label: `'foo` error[E0426]: use of undeclared label `'bor` --> $DIR/suggest-labels.rs:8:18 | +LL | 'bar: loop { + | ---- a label with a similar name is reachable LL | continue 'bor; | ^^^^ - | -help: a label with a similar name exists in this scope - | -LL | continue 'bar; - | ^^^^ + | | + | undeclared label `'bor` + | help: try using similarly named label: `'bar` error[E0426]: use of undeclared label `'longlable` --> $DIR/suggest-labels.rs:13:19 | +LL | 'longlabel1: loop { + | ----------- a label with a similar name is reachable LL | break 'longlable; | ^^^^^^^^^^ - | -help: a label with a similar name exists in this scope - | -LL | break 'longlabel1; - | ^^^^^^^^^^^ + | | + | undeclared label `'longlable` + | help: try using similarly named label: `'longlabel1` error: aborting due to 3 previous errors