pub rules: BlockCheckMode,
pub span: Span,
/// If true, then there may exist `break 'a` values that aim to
- /// break out of this block early. As of this writing, this is not
- /// currently permitted in Rust itself, but it is generated as
- /// part of `catch` statements.
+ /// break out of this block early.
+ /// Used by `'label {}` blocks and by `catch` statements.
pub targeted_by_break: bool,
/// If true, don't emit return value type errors as the parser had
/// to recover from a parse error so this block will not have an
enum LoopKind {
Loop(hir::LoopSource),
WhileLoop,
+ Block,
}
impl LoopKind {
LoopKind::Loop(hir::LoopSource::WhileLet) => "while let",
LoopKind::Loop(hir::LoopSource::ForLoop) => "for",
LoopKind::WhileLoop => "while",
+ LoopKind::Block => "block",
}
}
}
Normal,
Loop(LoopKind),
Closure,
+ LabeledBlock,
}
#[derive(Copy, Clone)]
hir::ExprClosure(.., b, _, _) => {
self.with_context(Closure, |v| v.visit_nested_body(b));
}
+ hir::ExprBlock(ref b, Some(_label)) => {
+ self.with_context(LabeledBlock, |v| v.visit_block(&b));
+ }
hir::ExprBreak(label, ref opt_expr) => {
let loop_id = match label.target_id.into() {
Ok(loop_id) => loop_id,
},
Err(hir::LoopIdError::UnresolvedLabel) => ast::DUMMY_NODE_ID,
};
+
if loop_id != ast::DUMMY_NODE_ID {
match self.hir_map.find(loop_id).unwrap() {
hir::map::NodeBlock(_) => return,
}
}
+ if self.cx == LabeledBlock {
+ return;
+ }
+
if opt_expr.is_some() {
let loop_kind = if loop_id == ast::DUMMY_NODE_ID {
None
Some(match self.hir_map.expect_expr(loop_id).node {
hir::ExprWhile(..) => LoopKind::WhileLoop,
hir::ExprLoop(_, _, source) => LoopKind::Loop(source),
+ hir::ExprBlock(..) => LoopKind::Block,
ref r => span_bug!(e.span,
"break label resolved to a non-loop: {:?}", r),
})
};
match loop_kind {
- None | Some(LoopKind::Loop(hir::LoopSource::Loop)) => (),
+ None |
+ Some(LoopKind::Loop(hir::LoopSource::Loop)) |
+ Some(LoopKind::Block) => (),
Some(kind) => {
struct_span_err!(self.sess, e.span, E0571,
"`break` with value from a `{}` loop",
kind.name())
.span_label(e.span,
- "can only break with a value inside `loop`")
+ "can only break with a value inside \
+ `loop` or breakable block")
.span_suggestion(e.span,
&format!("instead, use `break` on its own \
without a value inside this `{}` loop",
}
}
- self.require_loop("break", e.span);
+ self.require_break_cx("break", e.span);
}
hir::ExprAgain(label) => {
if let Err(hir::LoopIdError::UnlabeledCfInWhileCondition) = label.target_id {
self.emit_unlabled_cf_in_while_condition(e.span, "continue");
}
- self.require_loop("continue", e.span)
+ self.require_break_cx("continue", e.span)
},
_ => intravisit::walk_expr(self, e),
}
self.cx = old_cx;
}
- fn require_loop(&self, name: &str, span: Span) {
+ fn require_break_cx(&self, name: &str, span: Span) {
match self.cx {
+ LabeledBlock |
Loop(_) => {}
Closure => {
struct_span_err!(self.sess, span, E0267, "`{}` inside of a closure", name)