Avoid ICE when checking Destination
of break
inside a closure
This commit is contained in:
parent
237d54ff6c
commit
0585475efd
@ -566,7 +566,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// the `enclosing_loops` field and let's coerce the
|
// the `enclosing_loops` field and let's coerce the
|
||||||
// type of `expr_opt` into what is expected.
|
// type of `expr_opt` into what is expected.
|
||||||
let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
|
let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
|
||||||
let ctxt = enclosing_breakables.find_breakable(target_id);
|
let ctxt = match enclosing_breakables.opt_find_breakable(target_id) {
|
||||||
|
Some(ctxt) => ctxt,
|
||||||
|
None => { // Avoid ICE when `break` is inside a closure (#65383).
|
||||||
|
self.tcx.sess.delay_span_bug(
|
||||||
|
expr.span,
|
||||||
|
"break was outside loop, but no error was emitted",
|
||||||
|
);
|
||||||
|
return tcx.types.err;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(ref mut coerce) = ctxt.coerce {
|
if let Some(ref mut coerce) = ctxt.coerce {
|
||||||
if let Some(ref e) = expr_opt {
|
if let Some(ref e) = expr_opt {
|
||||||
coerce.coerce(self, &cause, e, e_ty);
|
coerce.coerce(self, &cause, e, e_ty);
|
||||||
@ -592,7 +602,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// If `ctxt.coerce` is `None`, we can just ignore
|
// If `ctxt.coerce` is `None`, we can just ignore
|
||||||
// the type of the expresison. This is because
|
// the type of the expression. This is because
|
||||||
// either this was a break *without* a value, in
|
// either this was a break *without* a value, in
|
||||||
// which case it is always a legal type (`()`), or
|
// which case it is always a legal type (`()`), or
|
||||||
// else an error would have been flagged by the
|
// else an error would have been flagged by the
|
||||||
|
@ -536,10 +536,16 @@ pub struct EnclosingBreakables<'tcx> {
|
|||||||
|
|
||||||
impl<'tcx> EnclosingBreakables<'tcx> {
|
impl<'tcx> EnclosingBreakables<'tcx> {
|
||||||
fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> {
|
fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> {
|
||||||
let ix = *self.by_id.get(&target_id).unwrap_or_else(|| {
|
self.opt_find_breakable(target_id).unwrap_or_else(|| {
|
||||||
bug!("could not find enclosing breakable with id {}", target_id);
|
bug!("could not find enclosing breakable with id {}", target_id);
|
||||||
});
|
})
|
||||||
&mut self.stack[ix]
|
}
|
||||||
|
|
||||||
|
fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> {
|
||||||
|
match self.by_id.get(&target_id) {
|
||||||
|
Some(ix) => Some(&mut self.stack[*ix]),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,4 +22,12 @@ fn main() {
|
|||||||
let rs: Foo = Foo{t: pth};
|
let rs: Foo = Foo{t: pth};
|
||||||
|
|
||||||
let unconstrained = break; //~ ERROR: `break` outside of a loop
|
let unconstrained = break; //~ ERROR: `break` outside of a loop
|
||||||
|
|
||||||
|
// This used to ICE because `target_id` passed to `check_expr_break` would be the closure and
|
||||||
|
// not the `loop`, which failed in the call to `find_breakable`. (#65383)
|
||||||
|
'lab: loop {
|
||||||
|
|| {
|
||||||
|
break 'lab; //~ ERROR `break` inside of a closure
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,15 @@ error[E0268]: `break` outside of a loop
|
|||||||
LL | let unconstrained = break;
|
LL | let unconstrained = break;
|
||||||
| ^^^^^ cannot `break` outside of a loop
|
| ^^^^^ cannot `break` outside of a loop
|
||||||
|
|
||||||
error: aborting due to 5 previous errors
|
error[E0267]: `break` inside of a closure
|
||||||
|
--> $DIR/break-outside-loop.rs:30:13
|
||||||
|
|
|
||||||
|
LL | || {
|
||||||
|
| -- enclosing closure
|
||||||
|
LL | break 'lab;
|
||||||
|
| ^^^^^^^^^^ cannot `break` inside of a closure
|
||||||
|
|
||||||
|
error: aborting due to 6 previous errors
|
||||||
|
|
||||||
Some errors have detailed explanations: E0267, E0268.
|
Some errors have detailed explanations: E0267, E0268.
|
||||||
For more information about an error, try `rustc --explain E0267`.
|
For more information about an error, try `rustc --explain E0267`.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user