mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 23:04:33 +00:00
resolve: disallow label use through closure/async
This commit modifies resolve to disallow `break`/`continue` to labels through closures or async blocks. This doesn't make sense and should have been prohibited anyway. Signed-off-by: David Wood <david@davidtw.co>
This commit is contained in:
parent
b7856f695d
commit
cb541dc12c
@ -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
|
||||
|
20
src/librustc_error_codes/error_codes/E0767.md
Normal file
20
src/librustc_error_codes/error_codes/E0767.md
Normal file
@ -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!
|
||||
}
|
||||
```
|
@ -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"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,10 @@ type Res = def::Res<ast::NodeId>;
|
||||
/// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,35 +732,79 @@ 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<P, R>(&self, mut ident: Ident, pred: P) -> Option<R>
|
||||
where
|
||||
P: Fn(&Rib<'_, NodeId>, Ident) -> Option<R>,
|
||||
{
|
||||
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<NodeId> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn resolve_adt(&mut self, item: &'ast Item, generics: &'ast Generics) {
|
||||
@ -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);
|
||||
}
|
||||
|
@ -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<LabelSuggestion> {
|
||||
// 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> {
|
||||
|
@ -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<Symbol>),
|
||||
UndeclaredLabel { name: &'a str, suggestion: Option<LabelSuggestion> },
|
||||
/// 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<LabelSuggestion> },
|
||||
}
|
||||
|
||||
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(..)
|
||||
|
@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -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`.
|
||||
|
7
src/test/ui/error-codes/E0767.rs
Normal file
7
src/test/ui/error-codes/E0767.rs
Normal file
@ -0,0 +1,7 @@
|
||||
fn main () {
|
||||
'a: loop {
|
||||
|| {
|
||||
loop { break 'a; } //~ ERROR E0767
|
||||
}
|
||||
}
|
||||
}
|
14
src/test/ui/error-codes/E0767.stderr
Normal file
14
src/test/ui/error-codes/E0767.stderr
Normal file
@ -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`.
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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`.
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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`.
|
||||
|
12
src/test/ui/issues/issue-73541-1.rs
Normal file
12
src/test/ui/issues/issue-73541-1.rs
Normal file
@ -0,0 +1,12 @@
|
||||
// edition:2018
|
||||
|
||||
fn main() {
|
||||
'a: loop {
|
||||
async {
|
||||
loop {
|
||||
continue 'a
|
||||
//~^ ERROR use of unreachable label `'a`
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
14
src/test/ui/issues/issue-73541-1.stderr
Normal file
14
src/test/ui/issues/issue-73541-1.stderr
Normal file
@ -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`.
|
20
src/test/ui/issues/issue-73541-2.rs
Normal file
20
src/test/ui/issues/issue-73541-2.rs
Normal file
@ -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() { }
|
18
src/test/ui/issues/issue-73541-2.stderr
Normal file
18
src/test/ui/issues/issue-73541-2.stderr
Normal file
@ -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`.
|
9
src/test/ui/issues/issue-73541-3.rs
Normal file
9
src/test/ui/issues/issue-73541-3.rs
Normal file
@ -0,0 +1,9 @@
|
||||
fn main() {
|
||||
'aaaaab: loop {
|
||||
|| {
|
||||
loop { continue 'aaaaaa }
|
||||
//~^ ERROR use of undeclared label `'aaaaaa`
|
||||
};
|
||||
|
||||
}
|
||||
}
|
12
src/test/ui/issues/issue-73541-3.stderr
Normal file
12
src/test/ui/issues/issue-73541-3.stderr
Normal file
@ -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`.
|
9
src/test/ui/issues/issue-73541.rs
Normal file
9
src/test/ui/issues/issue-73541.rs
Normal file
@ -0,0 +1,9 @@
|
||||
fn main() {
|
||||
'a: loop {
|
||||
|| {
|
||||
loop { continue 'a }
|
||||
//~^ ERROR use of unreachable label `'a`
|
||||
};
|
||||
|
||||
}
|
||||
}
|
14
src/test/ui/issues/issue-73541.stderr
Normal file
14
src/test/ui/issues/issue-73541.stderr
Normal file
@ -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`.
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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`.
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user