about summary refs log tree commit diff
path: root/tests/ui/codegen/issue-63787.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/codegen/issue-63787.rs')
-rw-r--r--tests/ui/codegen/issue-63787.rs36
1 files changed, 36 insertions, 0 deletions
diff --git a/tests/ui/codegen/issue-63787.rs b/tests/ui/codegen/issue-63787.rs
new file mode 100644
index 00000000000..cba079b2315
--- /dev/null
+++ b/tests/ui/codegen/issue-63787.rs
@@ -0,0 +1,36 @@
+// run-pass
+// compile-flags: -O
+
+// Make sure that `Ref` and `RefMut` do not make false promises about aliasing,
+// because once they drop, their reference/pointer can alias other writes.
+
+// Adapted from comex's proof of concept:
+// https://github.com/rust-lang/rust/issues/63787#issuecomment-523588164
+
+use std::cell::RefCell;
+use std::ops::Deref;
+
+pub fn break_if_r_is_noalias(rc: &RefCell<i32>, r: impl Deref<Target = i32>) -> i32 {
+    let ptr1 = &*r as *const i32;
+    let a = *r;
+    drop(r);
+    *rc.borrow_mut() = 2;
+    let r2 = rc.borrow();
+    let ptr2 = &*r2 as *const i32;
+    if ptr2 != ptr1 {
+        panic!();
+    }
+    // If LLVM knows the pointers are the same, and if `r` was `noalias`,
+    // then it may replace this with `a + a`, ignoring the earlier write.
+    a + *r2
+}
+
+fn main() {
+    let mut rc = RefCell::new(1);
+    let res = break_if_r_is_noalias(&rc, rc.borrow());
+    assert_eq!(res, 3);
+
+    *rc.get_mut() = 1;
+    let res = break_if_r_is_noalias(&rc, rc.borrow_mut());
+    assert_eq!(res, 3);
+}