diff options
| author | bors <bors@rust-lang.org> | 2023-02-27 11:41:41 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-02-27 11:41:41 +0000 |
| commit | 7d782b7ff4d57170e110211565209ecc5bbb3907 (patch) | |
| tree | 8554515c247bf460d6be7509310350d6fb750d4c | |
| parent | 49b9cc5139dd4d11ef78dc08c1f9170de5b1ca39 (diff) | |
| parent | bf46b9cb281cd196ca6227b2b72ef64dee390b5a (diff) | |
| download | rust-7d782b7ff4d57170e110211565209ecc5bbb3907.tar.gz rust-7d782b7ff4d57170e110211565209ecc5bbb3907.zip | |
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.
| -rw-r--r-- | compiler/rustc_const_eval/src/transform/validate.rs | 22 | ||||
| -rw-r--r-- | tests/ui/mir/validate/storage-live.rs | 30 | ||||
| -rw-r--r-- | tests/ui/mir/validate/storage-live.stderr | 13 |
3 files changed, 63 insertions, 2 deletions
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 068491646f4..fb37eb79a33 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -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 => {} 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 |
