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
|
||||
// type of `expr_opt` into what is expected.
|
||||
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 e) = expr_opt {
|
||||
coerce.coerce(self, &cause, e, e_ty);
|
||||
@ -592,7 +602,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
} else {
|
||||
// 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
|
||||
// which case it is always a legal type (`()`), or
|
||||
// else an error would have been flagged by the
|
||||
|
@ -536,10 +536,16 @@ pub struct EnclosingBreakables<'tcx> {
|
||||
|
||||
impl<'tcx> EnclosingBreakables<'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);
|
||||
});
|
||||
&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 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;
|
||||
| ^^^^^ 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.
|
||||
For more information about an error, try `rustc --explain E0267`.
|
||||
|
Loading…
x
Reference in New Issue
Block a user