Properly implement labeled breaks in while conditions

This commit is contained in:
Taylor Cramer 2017-02-15 23:28:59 -08:00
parent 5205e2f8b8
commit 4d65622dcd
12 changed files with 247 additions and 58 deletions

View file

@ -241,6 +241,22 @@ match 5u32 {
}
```
"##,
E0583: r##"
`break` or `continue` must include a label when used in the condition of a
`while` loop.
Example of erroneous code:
```compile_fail
while break {}
```
To fix this, add a label specifying which loop is being broken out of:
```
`foo: while break `foo {}
```
"##
}
register_diagnostics! {

View file

@ -87,11 +87,21 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
self.with_context(Closure, |v| v.visit_nested_body(b));
}
hir::ExprBreak(label, ref opt_expr) => {
let loop_id = match label.loop_id.into() {
Ok(loop_id) => loop_id,
Err(hir::LoopIdError::OutsideLoopScope) => ast::DUMMY_NODE_ID,
Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
self.emit_unlabled_cf_in_while_condition(e.span, "break");
ast::DUMMY_NODE_ID
},
Err(hir::LoopIdError::UnresolvedLabel) => ast::DUMMY_NODE_ID,
};
if opt_expr.is_some() {
let loop_kind = if label.loop_id == ast::DUMMY_NODE_ID {
let loop_kind = if loop_id == ast::DUMMY_NODE_ID {
None
} else {
Some(match self.hir_map.expect_expr(label.loop_id).node {
Some(match self.hir_map.expect_expr(loop_id).node {
hir::ExprWhile(..) => LoopKind::WhileLoop,
hir::ExprLoop(_, _, source) => LoopKind::Loop(source),
ref r => span_bug!(e.span,
@ -110,9 +120,15 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
}
}
}
self.require_loop("break", e.span);
}
hir::ExprAgain(_) => self.require_loop("continue", e.span),
hir::ExprAgain(label) => {
if let Err(hir::LoopIdError::UnlabeledCfInWhileCondition) = label.loop_id.into() {
self.emit_unlabled_cf_in_while_condition(e.span, "continue");
}
self.require_loop("continue", e.span)
},
_ => intravisit::walk_expr(self, e),
}
}
@ -143,4 +159,12 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
}
}
}
fn emit_unlabled_cf_in_while_condition(&mut self, span: Span, cf_type: &str) {
struct_span_err!(self.sess, span, E0583,
"`break` or `continue` with no label in the condition of a `while` loop")
.span_label(span,
&format!("unlabeled `{}` in the condition of a `while` loop", cf_type))
.emit();
}
}