about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFrank Steffahn <fdsteffahn@gmail.com>2025-01-11 22:18:52 +0100
committerFrank Steffahn <fdsteffahn@gmail.com>2025-01-11 22:36:25 +0100
commitdf57d65c708354d2e2549217a5fa4d7ca89eebfc (patch)
tree5f442abbfaa783f2a41dfcb0a00fd89c98c43385
parentfb65a3ee576feab95a632eb062f466d7a0342310 (diff)
downloadrust-df57d65c708354d2e2549217a5fa4d7ca89eebfc.tar.gz
rust-df57d65c708354d2e2549217a5fa4d7ca89eebfc.zip
Make UniqueRc invariant for soundness
-rw-r--r--library/alloc/src/rc.rs8
-rw-r--r--tests/ui/variance/variance-uniquerc.rs27
-rw-r--r--tests/ui/variance/variance-uniquerc.stderr15
3 files changed, 48 insertions, 2 deletions
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index 9256cb0703a..ae3318b839d 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -3708,7 +3708,11 @@ pub struct UniqueRc<
     #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
 > {
     ptr: NonNull<RcInner<T>>,
-    phantom: PhantomData<RcInner<T>>,
+    // Define the ownership of `RcInner<T>` for drop-check
+    _marker: PhantomData<RcInner<T>>,
+    // Invariance is necessary for soundness: once other `Weak`
+    // references exist, we already have a form of shared mutability!
+    _marker2: PhantomData<*mut T>,
     alloc: A,
 }
 
@@ -3994,7 +3998,7 @@ impl<T, A: Allocator> UniqueRc<T, A> {
             },
             alloc,
         ));
-        Self { ptr: ptr.into(), phantom: PhantomData, alloc }
+        Self { ptr: ptr.into(), _marker: PhantomData, _marker2: PhantomData, alloc }
     }
 }
 
diff --git a/tests/ui/variance/variance-uniquerc.rs b/tests/ui/variance/variance-uniquerc.rs
new file mode 100644
index 00000000000..0c395ab06ea
--- /dev/null
+++ b/tests/ui/variance/variance-uniquerc.rs
@@ -0,0 +1,27 @@
+// regression test of https://github.com/rust-lang/rust/pull/133572#issuecomment-2543007164
+// we should also test UniqueArc once implemented
+//
+// inline comments explain how this code *would* compile if UniqueRc was still covariant
+
+#![feature(unique_rc_arc)]
+
+use std::rc::UniqueRc;
+
+fn extend_lifetime<'a, 'b>(x: &'a str) -> &'b str {
+    let r = UniqueRc::new(""); // UniqueRc<&'static str>
+    let w = UniqueRc::downgrade(&r); // Weak<&'static str>
+    let mut r = r; // [IF COVARIANT]: ==>> UniqueRc<&'a str>
+    *r = x; // assign the &'a str
+    let _r = UniqueRc::into_rc(r); // Rc<&'a str>, but we only care to activate the weak
+    let r = w.upgrade().unwrap(); // Rc<&'static str>
+    *r // &'static str, coerces to &'b str
+    //~^ ERROR lifetime may not live long enough
+}
+
+fn main() {
+    let s = String::from("Hello World!");
+    let r = extend_lifetime(&s);
+    println!("{r}");
+    drop(s);
+    println!("{r}");
+}
diff --git a/tests/ui/variance/variance-uniquerc.stderr b/tests/ui/variance/variance-uniquerc.stderr
new file mode 100644
index 00000000000..1557f7e40c5
--- /dev/null
+++ b/tests/ui/variance/variance-uniquerc.stderr
@@ -0,0 +1,15 @@
+error: lifetime may not live long enough
+  --> $DIR/variance-uniquerc.rs:17:5
+   |
+LL | fn extend_lifetime<'a, 'b>(x: &'a str) -> &'b str {
+   |                    --  -- lifetime `'b` defined here
+   |                    |
+   |                    lifetime `'a` defined here
+...
+LL |     *r // &'static str, coerces to &'b str
+   |     ^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+   |
+   = help: consider adding the following bound: `'a: 'b`
+
+error: aborting due to 1 previous error
+