Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid ICE when checking Destination of break inside a closure #65518

Merged
merged 1 commit into from
Oct 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions src/librustc_typeck/check/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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
Expand Down
12 changes: 9 additions & 3 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
estebank marked this conversation as resolved.
Show resolved Hide resolved
Some(ix) => Some(&mut self.stack[*ix]),
None => None,
}
}
}

Expand Down
8 changes: 8 additions & 0 deletions src/test/ui/break-outside-loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
};
}
}
10 changes: 9 additions & 1 deletion src/test/ui/break-outside-loop.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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`.