Skip to content

Commit 7d782b7

Browse files
committed
Auto merge of #108175 - cjgillot:validate-storage, r=tmiasko
MIR-Validate StorageLive. `StorageLive` statements on a local which already has storage is banned by miri. This check is easy enough, and can detect bugs in MIR opts.
2 parents 49b9cc5 + bf46b9c commit 7d782b7

File tree

3 files changed

+63
-2
lines changed

3 files changed

+63
-2
lines changed

compiler/rustc_const_eval/src/transform/validate.rs

+20-2
Original file line numberDiff line numberDiff line change
@@ -755,8 +755,26 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
755755
self.fail(location, format!("explicit `{:?}` is forbidden", kind));
756756
}
757757
}
758-
StatementKind::StorageLive(..)
759-
| StatementKind::StorageDead(..)
758+
StatementKind::StorageLive(local) => {
759+
// We check that the local is not live when entering a `StorageLive` for it.
760+
// Technically, violating this restriction is only UB and not actually indicative
761+
// of not well-formed MIR. This means that an optimization which turns MIR that
762+
// already has UB into MIR that fails this check is not necessarily wrong. However,
763+
// we have no such optimizations at the moment, and so we include this check anyway
764+
// to help us catch bugs. If you happen to write an optimization that might cause
765+
// this to incorrectly fire, feel free to remove this check.
766+
if self.reachable_blocks.contains(location.block) {
767+
self.storage_liveness.seek_before_primary_effect(location);
768+
let locals_with_storage = self.storage_liveness.get();
769+
if locals_with_storage.contains(*local) {
770+
self.fail(
771+
location,
772+
format!("StorageLive({local:?}) which already has storage here"),
773+
);
774+
}
775+
}
776+
}
777+
StatementKind::StorageDead(_)
760778
| StatementKind::Coverage(_)
761779
| StatementKind::ConstEvalCounter
762780
| StatementKind::Nop => {}

tests/ui/mir/validate/storage-live.rs

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// compile-flags: -Zvalidate-mir -Ztreat-err-as-bug
2+
// failure-status: 101
3+
// error-pattern: broken MIR in
4+
// error-pattern: StorageLive(_1) which already has storage here
5+
// normalize-stderr-test "note: .*\n\n" -> ""
6+
// normalize-stderr-test "thread 'rustc' panicked.*\n" -> ""
7+
// normalize-stderr-test "storage_live\[....\]" -> "storage_live[HASH]"
8+
// rustc-env:RUST_BACKTRACE=0
9+
10+
#![feature(custom_mir, core_intrinsics)]
11+
12+
extern crate core;
13+
use core::intrinsics::mir::*;
14+
use core::ptr::{addr_of, addr_of_mut};
15+
16+
#[custom_mir(dialect = "built")]
17+
fn multiple_storage() {
18+
mir!(
19+
let a: usize;
20+
{
21+
StorageLive(a);
22+
StorageLive(a);
23+
Return()
24+
}
25+
)
26+
}
27+
28+
fn main() {
29+
multiple_storage()
30+
}
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
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]:
2+
StorageLive(_1) which already has storage here
3+
--> $DIR/storage-live.rs:22:13
4+
|
5+
LL | StorageLive(a);
6+
| ^^^^^^^^^^^^^^
7+
8+
error: the compiler unexpectedly panicked. this is a bug.
9+
10+
query stack during panic:
11+
#0 [mir_const] preparing `multiple_storage` for borrow checking
12+
#1 [mir_promoted] processing MIR for `multiple_storage`
13+
end of query stack

0 commit comments

Comments
 (0)