Skip to content

Commit

Permalink
Auto merge of #108175 - cjgillot:validate-storage, r=tmiasko
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bors committed Feb 27, 2023
2 parents 49b9cc5 + bf46b9c commit 7d782b7
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 2 deletions.
22 changes: 20 additions & 2 deletions compiler/rustc_const_eval/src/transform/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -755,8 +755,26 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
self.fail(location, format!("explicit `{:?}` is forbidden", kind));
}
}
StatementKind::StorageLive(..)
| StatementKind::StorageDead(..)
StatementKind::StorageLive(local) => {
// We check that the local is not live when entering a `StorageLive` for it.
// Technically, violating this restriction is only UB and not actually indicative
// of not well-formed MIR. This means that an optimization which turns MIR that
// already has UB into MIR that fails this check is not necessarily wrong. However,
// we have no such optimizations at the moment, and so we include this check anyway
// to help us catch bugs. If you happen to write an optimization that might cause
// this to incorrectly fire, feel free to remove this check.
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 => {}
Expand Down
30 changes: 30 additions & 0 deletions tests/ui/mir/validate/storage-live.rs
Original file line number Diff line number Diff line change
@@ -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()
}
13 changes: 13 additions & 0 deletions tests/ui/mir/validate/storage-live.stderr
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 7d782b7

Please sign in to comment.