about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_passes/src/loops.rs76
-rw-r--r--src/test/ui/label/label_misspelled.rs27
-rw-r--r--src/test/ui/label/label_misspelled.stderr78
-rw-r--r--src/test/ui/loops/loop-break-value-no-repeat.stderr4
-rw-r--r--src/test/ui/loops/loop-break-value.rs1
-rw-r--r--src/test/ui/loops/loop-break-value.stderr64
6 files changed, 175 insertions, 75 deletions
diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs
index ed3bfce510c..18b6b98e16a 100644
--- a/compiler/rustc_passes/src/loops.rs
+++ b/compiler/rustc_passes/src/loops.rs
@@ -90,47 +90,83 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
                 };
 
                 if let Some(Node::Block(_)) = loop_id.and_then(|id| self.hir_map.find(id)) {
-                        return;
-                    }
+                    return;
                 }
 
-                if opt_expr.is_some() {
-                    let loop_kind = if let Some(loop_id) = loop_id {
-                        Some(match self.hir_map.expect_expr(loop_id).kind {
-                            hir::ExprKind::Loop(_, _, source) => source,
+                if let Some(break_expr) = opt_expr {
+                    let (head, label, loop_kind) = if let Some(loop_id) = loop_id {
+                        match self.hir_map.expect_expr(loop_id).kind {
+                            hir::ExprKind::Loop(_, label, source, sp) => {
+                                (Some(sp), label, Some(source))
+                            }
                             ref r => {
                                 span_bug!(e.span, "break label resolved to a non-loop: {:?}", r)
                             }
-                        })
+                        }
                     } else {
-                        None
+                        (None, None, None)
                     };
                     match loop_kind {
                         None | Some(hir::LoopSource::Loop) => (),
                         Some(kind) => {
-                            struct_span_err!(
+                            let mut err = struct_span_err!(
                                 self.sess,
                                 e.span,
                                 E0571,
                                 "`break` with value from a `{}` loop",
                                 kind.name()
-                            )
-                            .span_label(
+                            );
+                            err.span_label(
                                 e.span,
-                                "can only break with a value inside \
-                                            `loop` or breakable block",
-                            )
-                            .span_suggestion(
+                                "can only break with a value inside `loop` or breakable block",
+                            );
+                            if let Some(head) = head {
+                                err.span_label(
+                                    head,
+                                    &format!(
+                                        "you can't `break` with a value in a `{}` loop",
+                                        kind.name()
+                                    ),
+                                );
+                            }
+                            err.span_suggestion(
                                 e.span,
                                 &format!(
-                                    "instead, use `break` on its own \
-                                        without a value inside this `{}` loop",
-                                    kind.name()
+                                    "use `break` on its own without a value inside this `{}` loop",
+                                    kind.name(),
                                 ),
                                 "break".to_string(),
                                 Applicability::MaybeIncorrect,
-                            )
-                            .emit();
+                            );
+                            if let Some(label) = label {
+                                match break_expr.kind {
+                                    hir::ExprKind::Path(hir::QPath::Resolved(
+                                        None,
+                                        hir::Path {
+                                            segments: [segment],
+                                            res: hir::def::Res::Err,
+                                            ..
+                                        },
+                                    )) if label.ident.to_string()
+                                        == format!("'{}", segment.ident) =>
+                                    {
+                                        // This error is redundant, we will have already emitted a
+                                        // suggestion to use the label when `segment` wasn't found
+                                        // (hence the `Res::Err` check).
+                                        err.delay_as_bug();
+                                    }
+                                    _ => {
+                                        err.span_suggestion(
+                                            break_expr.span,
+                                            "alternatively, you might have meant to use the \
+                                             available loop label",
+                                            label.ident.to_string(),
+                                            Applicability::MaybeIncorrect,
+                                        );
+                                    }
+                                }
+                            }
+                            err.emit();
                         }
                     }
                 }
diff --git a/src/test/ui/label/label_misspelled.rs b/src/test/ui/label/label_misspelled.rs
index 7a8ff0360f6..17c709768d5 100644
--- a/src/test/ui/label/label_misspelled.rs
+++ b/src/test/ui/label/label_misspelled.rs
@@ -1,8 +1,4 @@
 fn main() {
-    'LOOP: loop {
-        LOOP;
-        //~^ ERROR cannot find value `LOOP` in this scope
-    };
     'while_loop: while true { //~ WARN denote infinite loops with
         while_loop;
         //~^ ERROR cannot find value `while_loop` in this scope
@@ -15,6 +11,10 @@ fn main() {
         for_loop;
         //~^ ERROR cannot find value `for_loop` in this scope
     };
+    'LOOP: loop {
+        LOOP;
+        //~^ ERROR cannot find value `LOOP` in this scope
+    };
 }
 
 fn foo() {
@@ -25,16 +25,29 @@ fn foo() {
     'while_loop: while true { //~ WARN denote infinite loops with
         break while_loop;
         //~^ ERROR cannot find value `while_loop` in this scope
-        //~| ERROR `break` with value from a `while` loop
     };
     'while_let: while let Some(_) = Some(()) {
         break while_let;
         //~^ ERROR cannot find value `while_let` in this scope
-        //~| ERROR `break` with value from a `while` loop
     }
     'for_loop: for _ in 0..3 {
         break for_loop;
         //~^ ERROR cannot find value `for_loop` in this scope
-        //~| ERROR `break` with value from a `for` loop
+    };
+}
+
+fn bar() {
+    let foo = ();
+    'while_loop: while true { //~ WARN denote infinite loops with
+        break foo;
+        //~^ ERROR `break` with value from a `while` loop
+    };
+    'while_let: while let Some(_) = Some(()) {
+        break foo;
+        //~^ ERROR `break` with value from a `while` loop
+    }
+    'for_loop: for _ in 0..3 {
+        break foo;
+        //~^ ERROR `break` with value from a `for` loop
     };
 }
diff --git a/src/test/ui/label/label_misspelled.stderr b/src/test/ui/label/label_misspelled.stderr
index 7cfb6e8147d..3e99b0ff979 100644
--- a/src/test/ui/label/label_misspelled.stderr
+++ b/src/test/ui/label/label_misspelled.stderr
@@ -1,13 +1,5 @@
-error[E0425]: cannot find value `LOOP` in this scope
-  --> $DIR/label_misspelled.rs:3:9
-   |
-LL |     'LOOP: loop {
-   |     ----- a label with a similar name exists
-LL |         LOOP;
-   |         ^^^^ not found in this scope
-
 error[E0425]: cannot find value `while_loop` in this scope
-  --> $DIR/label_misspelled.rs:7:9
+  --> $DIR/label_misspelled.rs:3:9
    |
 LL |     'while_loop: while true {
    |     ----------- a label with a similar name exists
@@ -15,7 +7,7 @@ LL |         while_loop;
    |         ^^^^^^^^^^ not found in this scope
 
 error[E0425]: cannot find value `while_let` in this scope
-  --> $DIR/label_misspelled.rs:11:9
+  --> $DIR/label_misspelled.rs:7:9
    |
 LL |     'while_let: while let Some(_) = Some(()) {
    |     ---------- a label with a similar name exists
@@ -23,7 +15,7 @@ LL |         while_let;
    |         ^^^^^^^^^ not found in this scope
 
 error[E0425]: cannot find value `for_loop` in this scope
-  --> $DIR/label_misspelled.rs:15:9
+  --> $DIR/label_misspelled.rs:11:9
    |
 LL |     'for_loop: for _ in 0..3 {
    |     --------- a label with a similar name exists
@@ -31,6 +23,14 @@ LL |         for_loop;
    |         ^^^^^^^^ not found in this scope
 
 error[E0425]: cannot find value `LOOP` in this scope
+  --> $DIR/label_misspelled.rs:15:9
+   |
+LL |     'LOOP: loop {
+   |     ----- a label with a similar name exists
+LL |         LOOP;
+   |         ^^^^ not found in this scope
+
+error[E0425]: cannot find value `LOOP` in this scope
   --> $DIR/label_misspelled.rs:22:15
    |
 LL |     'LOOP: loop {
@@ -53,7 +53,7 @@ LL |         break while_loop;
    |               help: use the similarly named label: `'while_loop`
 
 error[E0425]: cannot find value `while_let` in this scope
-  --> $DIR/label_misspelled.rs:31:15
+  --> $DIR/label_misspelled.rs:30:15
    |
 LL |     'while_let: while let Some(_) = Some(()) {
    |     ---------- a label with a similar name exists
@@ -64,7 +64,7 @@ LL |         break while_let;
    |               help: use the similarly named label: `'while_let`
 
 error[E0425]: cannot find value `for_loop` in this scope
-  --> $DIR/label_misspelled.rs:36:15
+  --> $DIR/label_misspelled.rs:34:15
    |
 LL |     'for_loop: for _ in 0..3 {
    |     --------- a label with a similar name exists
@@ -75,7 +75,7 @@ LL |         break for_loop;
    |               help: use the similarly named label: `'for_loop`
 
 warning: denote infinite loops with `loop { ... }`
-  --> $DIR/label_misspelled.rs:6:5
+  --> $DIR/label_misspelled.rs:2:5
    |
 LL |     'while_loop: while true {
    |     ^^^^^^^^^^^^^^^^^^^^^^^ help: use `loop`
@@ -88,40 +88,64 @@ warning: denote infinite loops with `loop { ... }`
 LL |     'while_loop: while true {
    |     ^^^^^^^^^^^^^^^^^^^^^^^ help: use `loop`
 
+warning: denote infinite loops with `loop { ... }`
+  --> $DIR/label_misspelled.rs:41:5
+   |
+LL |     'while_loop: while true {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: use `loop`
+
 error[E0571]: `break` with value from a `while` loop
-  --> $DIR/label_misspelled.rs:26:9
+  --> $DIR/label_misspelled.rs:42:9
    |
-LL |         break while_loop;
-   |         ^^^^^^^^^^^^^^^^ can only break with a value inside `loop` or breakable block
+LL |     'while_loop: while true {
+   |     ----------------------- you can't `break` with a value in a `while` loop
+LL |         break foo;
+   |         ^^^^^^^^^ can only break with a value inside `loop` or breakable block
    |
-help: instead, use `break` on its own without a value inside this `while` loop
+help: use `break` on its own without a value inside this `while` loop
    |
 LL |         break;
    |         ^^^^^
+help: alternatively, you might have meant to use the available loop label
+   |
+LL |         break 'while_loop;
+   |               ^^^^^^^^^^^
 
 error[E0571]: `break` with value from a `while` loop
-  --> $DIR/label_misspelled.rs:31:9
+  --> $DIR/label_misspelled.rs:46:9
    |
-LL |         break while_let;
-   |         ^^^^^^^^^^^^^^^ can only break with a value inside `loop` or breakable block
+LL |     'while_let: while let Some(_) = Some(()) {
+   |     ---------------------------------------- you can't `break` with a value in a `while` loop
+LL |         break foo;
+   |         ^^^^^^^^^ can only break with a value inside `loop` or breakable block
    |
-help: instead, use `break` on its own without a value inside this `while` loop
+help: use `break` on its own without a value inside this `while` loop
    |
 LL |         break;
    |         ^^^^^
+help: alternatively, you might have meant to use the available loop label
+   |
+LL |         break 'while_let;
+   |               ^^^^^^^^^^
 
 error[E0571]: `break` with value from a `for` loop
-  --> $DIR/label_misspelled.rs:36:9
+  --> $DIR/label_misspelled.rs:50:9
    |
-LL |         break for_loop;
-   |         ^^^^^^^^^^^^^^ can only break with a value inside `loop` or breakable block
+LL |     'for_loop: for _ in 0..3 {
+   |     ------------------------ you can't `break` with a value in a `for` loop
+LL |         break foo;
+   |         ^^^^^^^^^ can only break with a value inside `loop` or breakable block
    |
-help: instead, use `break` on its own without a value inside this `for` loop
+help: use `break` on its own without a value inside this `for` loop
    |
 LL |         break;
    |         ^^^^^
+help: alternatively, you might have meant to use the available loop label
+   |
+LL |         break 'for_loop;
+   |               ^^^^^^^^^
 
-error: aborting due to 11 previous errors; 2 warnings emitted
+error: aborting due to 11 previous errors; 3 warnings emitted
 
 Some errors have detailed explanations: E0425, E0571.
 For more information about an error, try `rustc --explain E0425`.
diff --git a/src/test/ui/loops/loop-break-value-no-repeat.stderr b/src/test/ui/loops/loop-break-value-no-repeat.stderr
index ff93e9220e9..1c0d39a6e5a 100644
--- a/src/test/ui/loops/loop-break-value-no-repeat.stderr
+++ b/src/test/ui/loops/loop-break-value-no-repeat.stderr
@@ -1,10 +1,12 @@
 error[E0571]: `break` with value from a `for` loop
   --> $DIR/loop-break-value-no-repeat.rs:12:9
    |
+LL |     for _ in &[1,2,3] {
+   |     ----------------- you can't `break` with a value in a `for` loop
 LL |         break 22
    |         ^^^^^^^^ can only break with a value inside `loop` or breakable block
    |
-help: instead, use `break` on its own without a value inside this `for` loop
+help: use `break` on its own without a value inside this `for` loop
    |
 LL |         break
    |         ^^^^^
diff --git a/src/test/ui/loops/loop-break-value.rs b/src/test/ui/loops/loop-break-value.rs
index 8a080cfdf49..51c9a36a039 100644
--- a/src/test/ui/loops/loop-break-value.rs
+++ b/src/test/ui/loops/loop-break-value.rs
@@ -94,6 +94,5 @@ fn main() {
     'LOOP: for _ in 0 .. 9 {
         break LOOP;
         //~^ ERROR cannot find value `LOOP` in this scope
-        //~| ERROR `break` with value from a `for` loop
     }
 }
diff --git a/src/test/ui/loops/loop-break-value.stderr b/src/test/ui/loops/loop-break-value.stderr
index 27104118a63..c7cf1017d4b 100644
--- a/src/test/ui/loops/loop-break-value.stderr
+++ b/src/test/ui/loops/loop-break-value.stderr
@@ -20,32 +20,48 @@ LL |     'while_loop: while true {
 error[E0571]: `break` with value from a `while` loop
   --> $DIR/loop-break-value.rs:28:9
    |
+LL |     'while_loop: while true {
+   |     ----------------------- you can't `break` with a value in a `while` loop
+LL |         break;
 LL |         break ();
    |         ^^^^^^^^ can only break with a value inside `loop` or breakable block
    |
-help: instead, use `break` on its own without a value inside this `while` loop
+help: use `break` on its own without a value inside this `while` loop
    |
 LL |         break;
    |         ^^^^^
+help: alternatively, you might have meant to use the available loop label
+   |
+LL |         break 'while_loop;
+   |               ^^^^^^^^^^^
 
 error[E0571]: `break` with value from a `while` loop
   --> $DIR/loop-break-value.rs:30:13
    |
+LL |     'while_loop: while true {
+   |     ----------------------- you can't `break` with a value in a `while` loop
+...
 LL |             break 'while_loop 123;
    |             ^^^^^^^^^^^^^^^^^^^^^ can only break with a value inside `loop` or breakable block
    |
-help: instead, use `break` on its own without a value inside this `while` loop
+help: use `break` on its own without a value inside this `while` loop
    |
 LL |             break;
    |             ^^^^^
+help: alternatively, you might have meant to use the available loop label
+   |
+LL |             break 'while_loop 'while_loop;
+   |                               ^^^^^^^^^^^
 
 error[E0571]: `break` with value from a `while` loop
   --> $DIR/loop-break-value.rs:38:12
    |
+LL |     while let Some(_) = Some(()) {
+   |     ---------------------------- you can't `break` with a value in a `while` loop
 LL |         if break () {
    |            ^^^^^^^^ can only break with a value inside `loop` or breakable block
    |
-help: instead, use `break` on its own without a value inside this `while` loop
+help: use `break` on its own without a value inside this `while` loop
    |
 LL |         if break {
    |            ^^^^^
@@ -53,10 +69,12 @@ LL |         if break {
 error[E0571]: `break` with value from a `while` loop
   --> $DIR/loop-break-value.rs:43:9
    |
+LL |     while let Some(_) = Some(()) {
+   |     ---------------------------- you can't `break` with a value in a `while` loop
 LL |         break None;
    |         ^^^^^^^^^^ can only break with a value inside `loop` or breakable block
    |
-help: instead, use `break` on its own without a value inside this `while` loop
+help: use `break` on its own without a value inside this `while` loop
    |
 LL |         break;
    |         ^^^^^
@@ -64,21 +82,30 @@ LL |         break;
 error[E0571]: `break` with value from a `while` loop
   --> $DIR/loop-break-value.rs:49:13
    |
+LL |     'while_let_loop: while let Some(_) = Some(()) {
+   |     --------------------------------------------- you can't `break` with a value in a `while` loop
+LL |         loop {
 LL |             break 'while_let_loop "nope";
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can only break with a value inside `loop` or breakable block
    |
-help: instead, use `break` on its own without a value inside this `while` loop
+help: use `break` on its own without a value inside this `while` loop
    |
 LL |             break;
    |             ^^^^^
+help: alternatively, you might have meant to use the available loop label
+   |
+LL |             break 'while_let_loop 'while_let_loop;
+   |                                   ^^^^^^^^^^^^^^^
 
 error[E0571]: `break` with value from a `for` loop
   --> $DIR/loop-break-value.rs:56:9
    |
+LL |     for _ in &[1,2,3] {
+   |     ----------------- you can't `break` with a value in a `for` loop
 LL |         break ();
    |         ^^^^^^^^ can only break with a value inside `loop` or breakable block
    |
-help: instead, use `break` on its own without a value inside this `for` loop
+help: use `break` on its own without a value inside this `for` loop
    |
 LL |         break;
    |         ^^^^^
@@ -86,10 +113,13 @@ LL |         break;
 error[E0571]: `break` with value from a `for` loop
   --> $DIR/loop-break-value.rs:57:9
    |
+LL |     for _ in &[1,2,3] {
+   |     ----------------- you can't `break` with a value in a `for` loop
+LL |         break ();
 LL |         break [()];
    |         ^^^^^^^^^^ can only break with a value inside `loop` or breakable block
    |
-help: instead, use `break` on its own without a value inside this `for` loop
+help: use `break` on its own without a value inside this `for` loop
    |
 LL |         break;
    |         ^^^^^
@@ -97,24 +127,20 @@ LL |         break;
 error[E0571]: `break` with value from a `for` loop
   --> $DIR/loop-break-value.rs:64:13
    |
+LL |     'for_loop: for _ in &[1,2,3] {
+   |     ---------------------------- you can't `break` with a value in a `for` loop
+...
 LL |             break 'for_loop Some(17);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ can only break with a value inside `loop` or breakable block
    |
-help: instead, use `break` on its own without a value inside this `for` loop
+help: use `break` on its own without a value inside this `for` loop
    |
 LL |             break;
    |             ^^^^^
-
-error[E0571]: `break` with value from a `for` loop
-  --> $DIR/loop-break-value.rs:95:9
-   |
-LL |         break LOOP;
-   |         ^^^^^^^^^^ can only break with a value inside `loop` or breakable block
+help: alternatively, you might have meant to use the available loop label
    |
-help: instead, use `break` on its own without a value inside this `for` loop
-   |
-LL |         break;
-   |         ^^^^^
+LL |             break 'for_loop 'for_loop;
+   |                             ^^^^^^^^^
 
 error[E0308]: mismatched types
   --> $DIR/loop-break-value.rs:4:31
@@ -173,7 +199,7 @@ LL |         break;
    |         expected integer, found `()`
    |         help: give it a value of the expected type: `break value`
 
-error: aborting due to 18 previous errors; 1 warning emitted
+error: aborting due to 17 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0308, E0425, E0571.
 For more information about an error, try `rustc --explain E0308`.