In the implementation of Arc
, we find:
|
|
|
struct ArcInner<T: ?Sized> { |
|
strong: atomic::AtomicUsize, |
|
|
|
// the value usize::MAX acts as a sentinel for temporarily "locking" the |
|
// ability to upgrade weak pointers or downgrade strong ones; this is used |
|
// to avoid races in `make_mut` and `get_mut`. |
|
weak: atomic::AtomicUsize, |
|
|
|
data: T, |
|
} |
|
|
|
/// Computes the offset of the data field within ArcInner. |
|
unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize { |
|
// Align the unsized value to the end of the ArcInner. |
|
// Because it is ?Sized, it will always be the last field in memory. |
|
let align = align_of_val(&*ptr); |
|
let layout = Layout::new::<ArcInner<()>>(); |
|
(layout.size() + layout.padding_needed_for(align)) as isize |
|
} |
|
|
|
/// Computes the offset of the data field within ArcInner. |
|
/// |
|
/// Unlike [`data_offset`], this doesn't need the pointer, but it works only on `T: Sized`. |
|
fn data_offset_sized<T>() -> isize { |
|
let align = align_of::<T>(); |
|
let layout = Layout::new::<ArcInner<()>>(); |
|
(layout.size() + layout.padding_needed_for(align)) as isize |
|
} |
(And similarly in rc.rs
with struct RcBox
.)
Note the comment: Because it is ?Sized, it will always be the last field in memory.
Is this actually true, even for instantiations where T
happens to be Sized
? Does the language guarantee that there exist no type Foo
such that the fields of ArcInner<Foo>
would be re-ordered?
Or do we need to add #[repr(C)]
to ArcInner
and RcBox
?
CC @rust-lang/wg-unsafe-code-guidelines