about summary refs log tree commit diff
path: root/src/test/ui/drop
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-11-23 17:44:33 +0000
committerbors <bors@rust-lang.org>2021-11-23 17:44:33 +0000
commit7b3cd075bbe309031b418650a9c32baf0b4a3276 (patch)
tree3497a521d0204eb2a83f6659c429c50576ebd693 /src/test/ui/drop
parent311fa1f14dd8ffbbe83b229a94b17f7f1ecaf33b (diff)
parent22d937ddfc64bdf1f8724a27a782f2da2ae72be0 (diff)
downloadrust-7b3cd075bbe309031b418650a9c32baf0b4a3276.tar.gz
rust-7b3cd075bbe309031b418650a9c32baf0b4a3276.zip
Auto merge of #90788 - ecstatic-morse:issue-90752, r=wesleywiser
Mark places as initialized when mutably borrowed

Fixes the example in #90752, but does not handle some corner cases involving raw pointers and unsafe. See [this comment](https://github.com/rust-lang/rust/issues/90752#issuecomment-965822895) for more information, or the second test.

Although I talked about both `MaybeUninitializedPlaces` and `MaybeInitializedPlaces` in #90752, this PR only changes the latter. That's because "maybe uninitialized" is the conservative choice, and marking them as definitely initialized (`!maybe_uninitialized`) when a mutable borrow is created could lead to problems if `addr_of_mut` to an uninitialized local is allowed. Additionally, places cannot become uninitialized via a mutable reference, so if a place is definitely initialized, taking a mutable reference to it should not change that.

I think it's correct to ignore interior mutability as nbdd0121 suggests below. Their analysis doesn't work inside of `core::cell`, which *does* have access to `UnsafeCell`'s field, but that won't be an issue unless we explicitly instantiate one with an `enum` within that module.

r? `@wesleywiser`
Diffstat (limited to 'src/test/ui/drop')
-rw-r--r--src/test/ui/drop/issue-90752-raw-ptr-shenanigans.rs41
-rw-r--r--src/test/ui/drop/issue-90752.rs32
2 files changed, 73 insertions, 0 deletions
diff --git a/src/test/ui/drop/issue-90752-raw-ptr-shenanigans.rs b/src/test/ui/drop/issue-90752-raw-ptr-shenanigans.rs
new file mode 100644
index 00000000000..4e67b35949e
--- /dev/null
+++ b/src/test/ui/drop/issue-90752-raw-ptr-shenanigans.rs
@@ -0,0 +1,41 @@
+// run-pass
+
+use std::cell::RefCell;
+
+struct S<'a>(i32, &'a RefCell<Vec<i32>>);
+
+impl<'a> Drop for S<'a> {
+    fn drop(&mut self) {
+        self.1.borrow_mut().push(self.0);
+    }
+}
+
+fn test(drops: &RefCell<Vec<i32>>) {
+    let mut foo = None;
+    let pfoo: *mut _ = &mut foo;
+
+    match foo {
+        None => (),
+        _ => return,
+    }
+
+    // Both S(0) and S(1) should be dropped, but aren't.
+    unsafe { *pfoo = Some((S(0, drops), S(1, drops))); }
+
+    match foo {
+        Some((_x, _)) => {}
+        _ => {}
+    }
+}
+
+fn main() {
+    let drops = RefCell::new(Vec::new());
+    test(&drops);
+
+    // Ideally, we want this...
+    //assert_eq!(*drops.borrow(), &[0, 1]);
+
+    // But the delayed access through the raw pointer confuses drop elaboration,
+    // causing S(1) to be leaked.
+    assert_eq!(*drops.borrow(), &[0]);
+}
diff --git a/src/test/ui/drop/issue-90752.rs b/src/test/ui/drop/issue-90752.rs
new file mode 100644
index 00000000000..4395e45e773
--- /dev/null
+++ b/src/test/ui/drop/issue-90752.rs
@@ -0,0 +1,32 @@
+// run-pass
+
+use std::cell::RefCell;
+
+struct S<'a>(i32, &'a RefCell<Vec<i32>>);
+
+impl<'a> Drop for S<'a> {
+    fn drop(&mut self) {
+        self.1.borrow_mut().push(self.0);
+    }
+}
+
+fn test(drops: &RefCell<Vec<i32>>) {
+    let mut foo = None;
+    match foo {
+        None => (),
+        _ => return,
+    }
+
+    *(&mut foo) = Some((S(0, drops), S(1, drops))); // Both S(0) and S(1) should be dropped
+
+    match foo {
+        Some((_x, _)) => {}
+        _ => {}
+    }
+}
+
+fn main() {
+    let drops = RefCell::new(Vec::new());
+    test(&drops);
+    assert_eq!(*drops.borrow(), &[0, 1]);
+}