From 9aa4f6acb2e769ab012ab2cd7114177d94351847 Mon Sep 17 00:00:00 2001
From: Camille GILLOT <gillot.camille@gmail.com>
Date: Tue, 31 Jan 2023 17:14:04 +0000
Subject: [PATCH] MIR-Validate StorageLive.

---
 .../src/transform/validate.rs                 | 15 ++++++++--
 tests/ui/mir/validate/storage-live.rs         | 30 +++++++++++++++++++
 tests/ui/mir/validate/storage-live.stderr     | 13 ++++++++
 3 files changed, 56 insertions(+), 2 deletions(-)
 create mode 100644 tests/ui/mir/validate/storage-live.rs
 create mode 100644 tests/ui/mir/validate/storage-live.stderr

diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 3af2d0c4e66..be5b1aad13c 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -755,8 +755,19 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                     self.fail(location, format!("explicit `{:?}` is forbidden", kind));
                 }
             }
-            StatementKind::StorageLive(..)
-            | StatementKind::StorageDead(..)
+            StatementKind::StorageLive(local) => {
+                if self.reachable_blocks.contains(location.block) {
+                    self.storage_liveness.seek_before_primary_effect(location);
+                    let locals_with_storage = self.storage_liveness.get();
+                    if locals_with_storage.contains(*local) {
+                        self.fail(
+                            location,
+                            format!("StorageLive({local:?}) which already has storage here"),
+                        );
+                    }
+                }
+            }
+            StatementKind::StorageDead(_)
             | StatementKind::Coverage(_)
             | StatementKind::ConstEvalCounter
             | StatementKind::Nop => {}
diff --git a/tests/ui/mir/validate/storage-live.rs b/tests/ui/mir/validate/storage-live.rs
new file mode 100644
index 00000000000..ed3c26ed6da
--- /dev/null
+++ b/tests/ui/mir/validate/storage-live.rs
@@ -0,0 +1,30 @@
+// compile-flags: -Zvalidate-mir -Ztreat-err-as-bug
+// failure-status: 101
+// error-pattern: broken MIR in
+// error-pattern: StorageLive(_1) which already has storage here
+// normalize-stderr-test "note: .*\n\n" -> ""
+// normalize-stderr-test "thread 'rustc' panicked.*\n" -> ""
+// normalize-stderr-test "storage_live\[....\]" -> "storage_live[HASH]"
+// rustc-env:RUST_BACKTRACE=0
+
+#![feature(custom_mir, core_intrinsics)]
+
+extern crate core;
+use core::intrinsics::mir::*;
+use core::ptr::{addr_of, addr_of_mut};
+
+#[custom_mir(dialect = "built")]
+fn multiple_storage() {
+    mir!(
+        let a: usize;
+        {
+            StorageLive(a);
+            StorageLive(a);
+            Return()
+        }
+    )
+}
+
+fn main() {
+    multiple_storage()
+}
diff --git a/tests/ui/mir/validate/storage-live.stderr b/tests/ui/mir/validate/storage-live.stderr
new file mode 100644
index 00000000000..b586a865849
--- /dev/null
+++ b/tests/ui/mir/validate/storage-live.stderr
@@ -0,0 +1,13 @@
+error: internal compiler error: broken MIR in Item(WithOptConstParam { did: DefId(0:8 ~ storage_live[HASH]::multiple_storage), const_param_did: None }) (before pass CheckPackedRef) at bb0[1]:
+                                StorageLive(_1) which already has storage here
+  --> $DIR/storage-live.rs:22:13
+   |
+LL |             StorageLive(a);
+   |             ^^^^^^^^^^^^^^
+
+error: the compiler unexpectedly panicked. this is a bug.
+
+query stack during panic:
+#0 [mir_const] preparing `multiple_storage` for borrow checking
+#1 [mir_promoted] processing MIR for `multiple_storage`
+end of query stack