diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs index 4434def85ba..5dd11617b8b 100644 --- a/src/librustc_passes/diagnostics.rs +++ b/src/librustc_passes/diagnostics.rs @@ -308,4 +308,5 @@ register_diagnostics! { E0642, // patterns aren't allowed in methods without bodies E0666, // nested `impl Trait` is illegal E0667, // `impl Trait` in projections + E0696, // `continue` pointing to a labeled block } diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs index bd43cd71e41..eb8d416a8dd 100644 --- a/src/librustc_passes/loops.rs +++ b/src/librustc_passes/loops.rs @@ -152,8 +152,22 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { hir::ExprAgain(label) => { self.require_label_in_labeled_block(e.span, &label, "continue"); - if let Err(hir::LoopIdError::UnlabeledCfInWhileCondition) = label.target_id { - self.emit_unlabled_cf_in_while_condition(e.span, "continue"); + match label.target_id { + Ok(loop_id) => { + if let hir::map::NodeBlock(block) = self.hir_map.find(loop_id).unwrap() { + struct_span_err!(self.sess, e.span, E0696, + "`continue` pointing to a labeled block") + .span_label(e.span, + "labeled blocks cannot be `continue`'d") + .span_note(block.span, + "labeled block the continue points to") + .emit(); + } + } + Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => { + self.emit_unlabled_cf_in_while_condition(e.span, "continue"); + } + _ => {} } self.require_break_cx("continue", e.span) }, diff --git a/src/test/ui/label_break_value_continue.rs b/src/test/ui/label_break_value_continue.rs new file mode 100644 index 00000000000..10557d4bcd6 --- /dev/null +++ b/src/test/ui/label_break_value_continue.rs @@ -0,0 +1,34 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Simple continue pointing to an unlabeled break should yield in an error +fn continue_simple() { + 'b: { + continue; //~ ERROR unlabeled `continue` inside of a labeled block + } +} + +// Labeled continue pointing to an unlabeled break should yield in an error +fn continue_labeled() { + 'b: { + continue 'b; //~ ERROR `continue` pointing to a labeled block + } +} + +// Simple continue that would cross a labeled block should yield in an error +fn continue_crossing() { + loop { + 'b: { + continue; //~ ERROR unlabeled `continue` inside of a labeled block + } + } +} + +pub fn main() {} diff --git a/src/test/ui/label_break_value_continue.stderr b/src/test/ui/label_break_value_continue.stderr new file mode 100644 index 00000000000..cf707f1b960 --- /dev/null +++ b/src/test/ui/label_break_value_continue.stderr @@ -0,0 +1,30 @@ +error[E0695]: unlabeled `continue` inside of a labeled block + --> $DIR/label_break_value_continue.rs:14:9 + | +LL | continue; //~ ERROR unlabeled `continue` inside of a labeled block + | ^^^^^^^^ `continue` statements that would diverge to or through a labeled block need to bear a label + +error[E0696]: `continue` pointing to a labeled block + --> $DIR/label_break_value_continue.rs:21:9 + | +LL | continue 'b; //~ ERROR `continue` pointing to a labeled block + | ^^^^^^^^^^^ labeled blocks cannot be `continue`'d + | +note: labeled block the continue points to + --> $DIR/label_break_value_continue.rs:20:5 + | +LL | / 'b: { +LL | | continue 'b; //~ ERROR `continue` pointing to a labeled block +LL | | } + | |_____^ + +error[E0695]: unlabeled `continue` inside of a labeled block + --> $DIR/label_break_value_continue.rs:29:13 + | +LL | continue; //~ ERROR unlabeled `continue` inside of a labeled block + | ^^^^^^^^ `continue` statements that would diverge to or through a labeled block need to bear a label + +error: aborting due to 3 previous errors + +Some errors occurred: E0695, E0696. +For more information about an error, try `rustc --explain E0695`.