about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLeón Orell Valerian Liehr <me@fmease.dev>2023-10-30 10:48:20 +0100
committerGitHub <noreply@github.com>2023-10-30 10:48:20 +0100
commit4f4b38c40fde9bef29a0cca1452005d40b60738a (patch)
treecab7589b32d8aa7accd2ae2375c80c518e728afb
parent12eb539bf27fd96fa515b28e1dab28489f5ce027 (diff)
parent0c8bdd0bf33c2313ad9d0be495ffde8f4532237a (diff)
downloadrust-4f4b38c40fde9bef29a0cca1452005d40b60738a.tar.gz
rust-4f4b38c40fde9bef29a0cca1452005d40b60738a.zip
Rollup merge of #117382 - gurry:114529-ice-const-eval, r=oli-obk
Fail typeck for illegal break-with-value

This is fixes the issue wherein typeck was succeeding for break-with-value exprs at illegal locations such as inside `while`, `while let` and `for` loops which eventually caused an ICE during MIR interpretation for const eval.

Now we fail typeck for such code which prevents faulty MIR from being generated and interpreted, thus fixing the ICE.

Fixes #114529
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs13
-rw-r--r--tests/ui/typeck/issue-114529-illegal-break-with-value.rs20
-rw-r--r--tests/ui/typeck/issue-114529-illegal-break-with-value.stderr29
3 files changed, 58 insertions, 4 deletions
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index be225ceb843..b1d6e4f0523 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -625,10 +625,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                 };
 
-                // If the loop context is not a `loop { }`, then break with
-                // a value is illegal, and `opt_coerce_to` will be `None`.
-                // Just set expectation to error in that case.
-                let coerce_to = opt_coerce_to.unwrap_or_else(|| Ty::new_misc_error(tcx));
+                let coerce_to = match opt_coerce_to {
+                    Some(c) => c,
+                    None => {
+                        // If the loop context is not a `loop { }`, then break with
+                        // a value is illegal, and `opt_coerce_to` will be `None`.
+                        // Return error in that case (#114529).
+                        return Ty::new_misc_error(tcx);
+                    }
+                };
 
                 // Recurse without `enclosing_breakables` borrowed.
                 e_ty = self.check_expr_with_hint(e, coerce_to);
diff --git a/tests/ui/typeck/issue-114529-illegal-break-with-value.rs b/tests/ui/typeck/issue-114529-illegal-break-with-value.rs
new file mode 100644
index 00000000000..613d1b6343a
--- /dev/null
+++ b/tests/ui/typeck/issue-114529-illegal-break-with-value.rs
@@ -0,0 +1,20 @@
+// Regression test for issue #114529
+// Tests that we do not ICE during const eval for a
+// break-with-value in contexts where it is illegal
+
+#[allow(while_true)]
+fn main() {
+    [(); {
+        while true {
+            break 9; //~ ERROR `break` with value from a `while` loop
+        };
+        51
+    }];
+
+    [(); {
+        while let Some(v) = Some(9) {
+            break v; //~ ERROR `break` with value from a `while` loop
+        };
+        51
+    }];
+}
diff --git a/tests/ui/typeck/issue-114529-illegal-break-with-value.stderr b/tests/ui/typeck/issue-114529-illegal-break-with-value.stderr
new file mode 100644
index 00000000000..4d6c27bbbd0
--- /dev/null
+++ b/tests/ui/typeck/issue-114529-illegal-break-with-value.stderr
@@ -0,0 +1,29 @@
+error[E0571]: `break` with value from a `while` loop
+  --> $DIR/issue-114529-illegal-break-with-value.rs:9:13
+   |
+LL |         while true {
+   |         ---------- you can't `break` with a value in a `while` loop
+LL |             break 9;
+   |             ^^^^^^^ can only break with a value inside `loop` or breakable block
+   |
+help: use `break` on its own without a value inside this `while` loop
+   |
+LL |             break;
+   |             ~~~~~
+
+error[E0571]: `break` with value from a `while` loop
+  --> $DIR/issue-114529-illegal-break-with-value.rs:16:13
+   |
+LL |         while let Some(v) = Some(9) {
+   |         --------------------------- you can't `break` with a value in a `while` loop
+LL |             break v;
+   |             ^^^^^^^ can only break with a value inside `loop` or breakable block
+   |
+help: use `break` on its own without a value inside this `while` loop
+   |
+LL |             break;
+   |             ~~~~~
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0571`.