Skip to content

Commit

Permalink
Clearly document intentional UB in mir-opt tests
Browse files Browse the repository at this point in the history
Co-authored-by: Jakob Degen <jakob.e.degen@gmail.com>
  • Loading branch information
saethlin and JakobDegen committed Feb 13, 2023
1 parent 8dabf5d commit 614df3f
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 27 deletions.
10 changes: 10 additions & 0 deletions tests/mir-opt/copy-prop/mutate_through_pointer.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
// This attempts to mutate `a` via a pointer derived from `addr_of!(a)`. That is UB
// according to Miri. However, the decision to make this UB - and to allow
// rustc to rely on that fact for the purpose of optimizations - has not been
// finalized.
//
// As such, we include this test to ensure that copy prop does not rely on that
// fact. Specifically, if `addr_of!(a)` could not be used to modify a, it would
// be correct for CopyProp to replace all occurrences of `a` with `c` - but that
// would cause `f(true)` to output `false` instead of `true`.

#![feature(custom_mir, core_intrinsics)]
#![allow(unused_assignments)]
extern crate core;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
_5 = _3; // scope 3 at $DIR/sibling_ptr.rs:+4:10: +4:11
_4 = ptr::mut_ptr::<impl *mut u8>::add(move _5, const 1_usize) -> bb1; // scope 3 at $DIR/sibling_ptr.rs:+4:10: +4:18
// mir::Constant
// + span: $DIR/sibling_ptr.rs:8:12: 8:15
// + span: $DIR/sibling_ptr.rs:15:12: 15:15
// + literal: Const { ty: unsafe fn(*mut u8, usize) -> *mut u8 {ptr::mut_ptr::<impl *mut u8>::add}, val: Value(<ZST>) }
}

Expand Down
9 changes: 8 additions & 1 deletion tests/mir-opt/dataflow-const-prop/sibling_ptr.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
// This attempts to modify `x.1` via a pointer derived from `addr_of_mut!(x.0)`.
// According to Miri, that is UB. However, T-opsem has not finalized that
// decision and as such we cannot rely on it in optimizations. Consequently,
// DataflowConstProp must treat the `addr_of_mut!(x.0)` as potentially being
// used to modify `x.1` - if it did not, then it might incorrectly assume that it
// can infer the value of `x.1` at the end of this function.

// unit-test: DataflowConstProp

// EMIT_MIR sibling_ptr.main.DataflowConstProp.diff
Expand All @@ -7,5 +14,5 @@ fn main() {
let p = std::ptr::addr_of_mut!(x.0);
*p.add(1) = 1;
}
let x1 = x.1; // should not be propagated
let x1 = x.1; // should not be propagated
}
48 changes: 24 additions & 24 deletions tests/mir-opt/sroa.escaping.ScalarReplacementOfAggregates.diff
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,42 @@

fn escaping() -> () {
let mut _0: (); // return place in scope 0 at $DIR/sroa.rs:+0:19: +0:19
let _1: (); // in scope 0 at $DIR/sroa.rs:+2:5: +2:42
let mut _2: *const u32; // in scope 0 at $DIR/sroa.rs:+2:7: +2:41
let _3: &u32; // in scope 0 at $DIR/sroa.rs:+2:7: +2:41
let _4: Escaping; // in scope 0 at $DIR/sroa.rs:+2:8: +2:39
let mut _5: u32; // in scope 0 at $DIR/sroa.rs:+2:34: +2:37
let _1: (); // in scope 0 at $DIR/sroa.rs:+1:5: +1:42
let mut _2: *const u32; // in scope 0 at $DIR/sroa.rs:+1:7: +1:41
let _3: &u32; // in scope 0 at $DIR/sroa.rs:+1:7: +1:41
let _4: Escaping; // in scope 0 at $DIR/sroa.rs:+1:8: +1:39
let mut _5: u32; // in scope 0 at $DIR/sroa.rs:+1:34: +1:37

bb0: {
StorageLive(_1); // scope 0 at $DIR/sroa.rs:+2:5: +2:42
StorageLive(_2); // scope 0 at $DIR/sroa.rs:+2:7: +2:41
StorageLive(_3); // scope 0 at $DIR/sroa.rs:+2:7: +2:41
StorageLive(_4); // scope 0 at $DIR/sroa.rs:+2:8: +2:39
StorageLive(_5); // scope 0 at $DIR/sroa.rs:+2:34: +2:37
_5 = g() -> bb1; // scope 0 at $DIR/sroa.rs:+2:34: +2:37
StorageLive(_1); // scope 0 at $DIR/sroa.rs:+1:5: +1:42
StorageLive(_2); // scope 0 at $DIR/sroa.rs:+1:7: +1:41
StorageLive(_3); // scope 0 at $DIR/sroa.rs:+1:7: +1:41
StorageLive(_4); // scope 0 at $DIR/sroa.rs:+1:8: +1:39
StorageLive(_5); // scope 0 at $DIR/sroa.rs:+1:34: +1:37
_5 = g() -> bb1; // scope 0 at $DIR/sroa.rs:+1:34: +1:37
// mir::Constant
// + span: $DIR/sroa.rs:73:34: 73:35
// + span: $DIR/sroa.rs:78:34: 78:35
// + literal: Const { ty: fn() -> u32 {g}, val: Value(<ZST>) }
}

bb1: {
_4 = Escaping { a: const 1_u32, b: const 2_u32, c: move _5 }; // scope 0 at $DIR/sroa.rs:+2:8: +2:39
StorageDead(_5); // scope 0 at $DIR/sroa.rs:+2:38: +2:39
_3 = &(_4.0: u32); // scope 0 at $DIR/sroa.rs:+2:7: +2:41
_2 = &raw const (*_3); // scope 0 at $DIR/sroa.rs:+2:7: +2:41
_1 = f(move _2) -> bb2; // scope 0 at $DIR/sroa.rs:+2:5: +2:42
_4 = Escaping { a: const 1_u32, b: const 2_u32, c: move _5 }; // scope 0 at $DIR/sroa.rs:+1:8: +1:39
StorageDead(_5); // scope 0 at $DIR/sroa.rs:+1:38: +1:39
_3 = &(_4.0: u32); // scope 0 at $DIR/sroa.rs:+1:7: +1:41
_2 = &raw const (*_3); // scope 0 at $DIR/sroa.rs:+1:7: +1:41
_1 = f(move _2) -> bb2; // scope 0 at $DIR/sroa.rs:+1:5: +1:42
// mir::Constant
// + span: $DIR/sroa.rs:73:5: 73:6
// + span: $DIR/sroa.rs:78:5: 78:6
// + literal: Const { ty: fn(*const u32) {f}, val: Value(<ZST>) }
}

bb2: {
StorageDead(_2); // scope 0 at $DIR/sroa.rs:+2:41: +2:42
StorageDead(_4); // scope 0 at $DIR/sroa.rs:+2:42: +2:43
StorageDead(_3); // scope 0 at $DIR/sroa.rs:+2:42: +2:43
StorageDead(_1); // scope 0 at $DIR/sroa.rs:+2:42: +2:43
_0 = const (); // scope 0 at $DIR/sroa.rs:+0:19: +3:2
return; // scope 0 at $DIR/sroa.rs:+3:2: +3:2
StorageDead(_2); // scope 0 at $DIR/sroa.rs:+1:41: +1:42
StorageDead(_4); // scope 0 at $DIR/sroa.rs:+1:42: +1:43
StorageDead(_3); // scope 0 at $DIR/sroa.rs:+1:42: +1:43
StorageDead(_1); // scope 0 at $DIR/sroa.rs:+1:42: +1:43
_0 = const (); // scope 0 at $DIR/sroa.rs:+0:19: +2:2
return; // scope 0 at $DIR/sroa.rs:+2:2: +2:2
}
}

7 changes: 6 additions & 1 deletion tests/mir-opt/sroa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,13 @@ fn f(a: *const u32) {
println!("{}", unsafe { *a.add(2) });
}

// `f` uses the `&e.a` to access `e.c`. This is UB according to Miri today; however,
// T-opsem has not finalized that decision and as such rustc should not rely on
// it. If SROA were to rely on it, it would be (almost) correct to turn `e` into
// three distinct locals - one for each field - and pass a reference to only one
// of them to `f`. However, this would lead to a miscompilation because `b` and `c`
// might no longer appear right after `a` in memory.
pub fn escaping() {
// Verify this struct is not flattened.
f(&Escaping { a: 1, b: 2, c: g() }.a);
}

Expand Down

0 comments on commit 614df3f

Please sign in to comment.