Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 9310c96

Browse files
committedMar 3, 2025·
Make UniqueArc invariant for soundness
1 parent e0b9347 commit 9310c96

File tree

4 files changed

+49
-3
lines changed

4 files changed

+49
-3
lines changed
 

‎library/alloc/src/sync.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -4071,7 +4071,11 @@ pub struct UniqueArc<
40714071
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
40724072
> {
40734073
ptr: NonNull<ArcInner<T>>,
4074-
phantom: PhantomData<ArcInner<T>>,
4074+
// Define the ownership of `ArcInner<T>` for drop-check
4075+
_marker: PhantomData<ArcInner<T>>,
4076+
// Invariance is necessary for soundness: once other `Weak`
4077+
// references exist, we already have a form of shared mutability!
4078+
_marker2: PhantomData<*mut T>,
40754079
alloc: A,
40764080
}
40774081

@@ -4116,7 +4120,7 @@ impl<T, A: Allocator> UniqueArc<T, A> {
41164120
},
41174121
alloc,
41184122
));
4119-
Self { ptr: ptr.into(), phantom: PhantomData, alloc }
4123+
Self { ptr: ptr.into(), _marker: PhantomData, _marker2: PhantomData, alloc }
41204124
}
41214125
}
41224126

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// regression test of https://github.com/rust-lang/rust/pull/133572#issuecomment-2543007164
2+
// see also the test for UniqueRc` in variance-uniquerc.rs
3+
//
4+
// inline comments explain how this code *would* compile if UniqueArc was still covariant
5+
6+
#![feature(unique_rc_arc)]
7+
8+
use std::sync::UniqueArc;
9+
10+
fn extend_lifetime<'a, 'b>(x: &'a str) -> &'b str {
11+
let r = UniqueArc::new(""); // UniqueArc<&'static str>
12+
let w = UniqueArc::downgrade(&r); // Weak<&'static str>
13+
let mut r = r; // [IF COVARIANT]: ==>> UniqueArc<&'a str>
14+
*r = x; // assign the &'a str
15+
let _r = UniqueArc::into_arc(r); // Arc<&'a str>, but we only care to activate the weak
16+
let r = w.upgrade().unwrap(); // Arc<&'static str>
17+
*r // &'static str, coerces to &'b str
18+
//~^ ERROR lifetime may not live long enough
19+
}
20+
21+
fn main() {
22+
let s = String::from("Hello World!");
23+
let r = extend_lifetime(&s);
24+
println!("{r}");
25+
drop(s);
26+
println!("{r}");
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: lifetime may not live long enough
2+
--> $DIR/variance-uniquearc.rs:17:5
3+
|
4+
LL | fn extend_lifetime<'a, 'b>(x: &'a str) -> &'b str {
5+
| -- -- lifetime `'b` defined here
6+
| |
7+
| lifetime `'a` defined here
8+
...
9+
LL | *r // &'static str, coerces to &'b str
10+
| ^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
11+
|
12+
= help: consider adding the following bound: `'a: 'b`
13+
14+
error: aborting due to 1 previous error
15+

‎tests/ui/variance/variance-uniquerc.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// regression test of https://github.com/rust-lang/rust/pull/133572#issuecomment-2543007164
2-
// we should also test UniqueArc once implemented
2+
// see also the test for UniqueArc in variance-uniquearc.rs
33
//
44
// inline comments explain how this code *would* compile if UniqueRc was still covariant
55

0 commit comments

Comments
 (0)
Please sign in to comment.