Skip to content

Commit f45a227

Browse files
authored
TransparentWrapper supports UnsafeCell variance (#1024)
This will allow us to implement `TransparentWrapper` for `T` where `T` and `T::Inner` do not have `UnsafeCell`s at the same byte ranges. This, in turn, will let us automatically implement traits for these types so long as those traits don't require reasoning about `UnsafeCell` ranges (in other words, all traits other than `NoCell`).
1 parent 88c0edd commit f45a227

File tree

3 files changed

+52
-36
lines changed

3 files changed

+52
-36
lines changed

src/macros.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -247,11 +247,12 @@ macro_rules! impl_for_transparent_wrapper {
247247
}
248248
};
249249
(@is_transparent_wrapper NoCell) => {
250-
// SAFETY: `W: TransparentWrapper` requires that `W` has `UnsafeCell`s
251-
// at the same byte offsets as `W::Inner = T`. `T: NoCell` implies that
252-
// `T` does not contain any `UnsafeCell`s, and so `W` does not contain
253-
// any `UnsafeCell`s. Thus, `W` can soundly implement `NoCell`.
254-
fn is_transparent_wrapper<I: Invariants, T: ?Sized, W: TransparentWrapper<I, Inner=T> + ?Sized>() {}
250+
// SAFETY: `W: TransparentWrapper<UnsafeCellVariance=Covariant>`
251+
// requires that `W` has `UnsafeCell`s at the same byte offsets as
252+
// `W::Inner = T`. `T: NoCell` implies that `T` does not contain any
253+
// `UnsafeCell`s, and so `W` does not contain any `UnsafeCell`s. Thus,
254+
// `W` can soundly implement `NoCell`.
255+
fn is_transparent_wrapper<I: Invariants, T: ?Sized, W: TransparentWrapper<I, Inner=T, UnsafeCellVariance=Covariant> + ?Sized>() {}
255256
};
256257
(@is_transparent_wrapper FromZeros) => {
257258
// SAFETY: `W: TransparentWrapper<ValidityVariance=Covariant>` requires

src/pointer/ptr.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ mod _external {
389389
/// Methods for converting to and from `Ptr` and Rust's safe reference types.
390390
mod _conversions {
391391
use super::*;
392-
use crate::util::{AlignmentVariance, TransparentWrapper, ValidityVariance};
392+
use crate::util::{AlignmentVariance, Covariant, TransparentWrapper, ValidityVariance};
393393

394394
/// `&'a T` → `Ptr<'a, T>`
395395
impl<'a, T> Ptr<'a, T, (invariant::Shared, invariant::Aligned, invariant::Valid)>
@@ -609,7 +609,7 @@ mod _conversions {
609609
/// `Ptr<'a, T = Wrapper<U>>` → `Ptr<'a, U>`
610610
impl<'a, T, I> Ptr<'a, T, I>
611611
where
612-
T: 'a + TransparentWrapper<I> + ?Sized,
612+
T: 'a + TransparentWrapper<I, UnsafeCellVariance = Covariant> + ?Sized,
613613
I: Invariants,
614614
{
615615
/// Converts the `Ptr` to a transparent wrapper type into a `Ptr` to the
@@ -629,8 +629,9 @@ mod _conversions {
629629
// - By invariant on `TransparentWrapper::cast_into_inner`:
630630
// - This cast preserves the referent's size.
631631
// - This cast preserves provenance.
632-
// - By invariant on `TransparentWrapper`, `T` and `T::Inner` have
633-
// `UnsafeCell`s at the same byte ranges.
632+
// - By invariant on `TransparentWrapper<UnsafeCellVariance =
633+
// Covariant>`, `T` and `T::Inner` have `UnsafeCell`s at the same
634+
// byte ranges.
634635
let c = unsafe { self.cast_unsized(|p| T::cast_into_inner(p)) };
635636
// SAFETY: By invariant on `TransparentWrapper`, since `self`
636637
// satisfies the alignment invariant `I::Alignment`, `c` (of type

src/util.rs

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,12 @@ use crate::{
2626
///
2727
/// # Safety
2828
///
29-
/// `T: TransparentWrapper` implies that:
30-
/// - `T` has the same size as [`T::Inner`]
31-
/// - `T` has `UnsafeCell`s covering the same byte ranges as `T::Inner`
32-
/// - `T` has zero-sized `UnsafeCell`s (e.g., `UnsafeCell<()>`,
33-
/// `[UnsafeCell<u8>; 0]`, etc) at the same byte offsets as `T::Inner`
34-
///
29+
/// `T: TransparentWrapper` implies that `T` has the same size as [`T::Inner`].
3530
/// Further, `T: TransparentWrapper<I>` implies that:
31+
/// - If `T::UnsafeCellVariance = Covariant`, then:
32+
/// - `T` has `UnsafeCell`s covering the same byte ranges as `T::Inner`
33+
/// - `T` has zero-sized `UnsafeCell`s (e.g., `UnsafeCell<()>`,
34+
/// `[UnsafeCell<u8>; 0]`, etc) at the same byte offsets as `T::Inner`
3635
/// - If a `T` pointer satisfies the alignment invariant `I::Alignment`, then
3736
/// that same pointer, cast to `T::Inner`, satisfies the alignment invariant
3837
/// `<T::AlignmentVariance as AlignmentVariance<I::Alignment>>::Applied`.
@@ -48,6 +47,7 @@ use crate::{
4847
pub unsafe trait TransparentWrapper<I: Invariants> {
4948
type Inner: ?Sized;
5049

50+
type UnsafeCellVariance;
5151
type AlignmentVariance: AlignmentVariance<I::Alignment>;
5252
type ValidityVariance: ValidityVariance<I::Validity>;
5353

@@ -106,14 +106,17 @@ impl<I: invariant::Validity> ValidityVariance<I> for Invariant {
106106

107107
// SAFETY:
108108
// - Per [1], `MaybeUninit<T>` has the same size as `T`.
109-
// - Per [1], `MaybeUninit<T>` has `UnsafeCell`s at the same byte ranges as
110-
// `Inner = T`, and `UnsafeCell`s at the same byte offsets as `T`.
111109
// - See inline comments for other safety justifications.
112110
//
113111
// [1] TODO(#896): Write a safety proof before the next stable release.
114112
unsafe impl<T, I: Invariants> TransparentWrapper<I> for MaybeUninit<T> {
115113
type Inner = T;
116114

115+
// SAFETY: Per [1], `MaybeUninit<T>` has `UnsafeCell`s at the same byte
116+
// ranges as `Inner = T`, and `UnsafeCell`s at the same byte offsets as `T`.
117+
//
118+
// [1] TODO(#896): Write a safety proof before the next stable release.
119+
type UnsafeCellVariance = Covariant;
117120
// SAFETY: Per [1], `MaybeUninit<T>` has the same layout as `T`, and thus
118121
// has the same alignment as `T`.
119122
//
@@ -145,14 +148,17 @@ unsafe impl<T, I: Invariants> TransparentWrapper<I> for MaybeUninit<T> {
145148

146149
// SAFETY:
147150
// - Per [1], `ManuallyDrop<T>` has the same size as `T`.
148-
// - Per [1], `ManuallyDrop<T>` has `UnsafeCell`s at the same byte ranges as
149-
// `Inner = T`, and `UnsafeCell`s at the same byte offsets as `T`.
150151
// - See inline comments for other safety justifications.
151152
//
152153
// [1] TODO(#896): Write a safety proof before the next stable release.
153154
unsafe impl<T: ?Sized, I: Invariants> TransparentWrapper<I> for ManuallyDrop<T> {
154155
type Inner = T;
155156

157+
// SAFETY: Per [1], `ManuallyDrop<T>` has `UnsafeCell`s at the same byte
158+
// ranges as `Inner = T`, and `UnsafeCell`s at the same byte offsets as `T`.
159+
//
160+
// [1] TODO(#896): Write a safety proof before the next stable release.
161+
type UnsafeCellVariance = Covariant;
156162
// SAFETY: Per [1], `ManuallyDrop<T>` has the same layout as `T`, and thus
157163
// has the same alignment as `T`.
158164
//
@@ -187,14 +193,17 @@ unsafe impl<T: ?Sized, I: Invariants> TransparentWrapper<I> for ManuallyDrop<T>
187193

188194
// SAFETY:
189195
// - Per [1], `Wrapping<T>` has the same size as `T`.
190-
// - Per [1], `Wrapping<T>` has `UnsafeCell`s at the same byte ranges as `Inner
191-
// = T`, and `UnsafeCell`s at the same byte offsets as `T`.
192196
// - See inline comments for other safety justifications.
193197
//
194198
// [1] TODO(#896): Write a safety proof before the next stable release.
195199
unsafe impl<T, I: Invariants> TransparentWrapper<I> for Wrapping<T> {
196200
type Inner = T;
197201

202+
// SAFETY: Per [1], `Wrapping<T>` has `UnsafeCell`s at the same byte ranges
203+
// as `Inner = T`, and `UnsafeCell`s at the same byte offsets as `T`.
204+
//
205+
// [1] TODO(#896): Write a safety proof before the next stable release.
206+
type UnsafeCellVariance = Covariant;
198207
// SAFETY: Per [1], `Wrapping<T>` has the same layout as `T`, and thus has
199208
// the same alignment as `T`.
200209
//
@@ -235,14 +244,17 @@ unsafe impl<T, I: Invariants> TransparentWrapper<I> for Wrapping<T> {
235244
}
236245

237246
// SAFETY: We define `Unalign<T>` to be a `#[repr(C, packed)]` type wrapping a
238-
// single `T` field. Thus, `Unalign<T>` has the same size as `T`, has
239-
// `UnsafeCell`s at the same byte ranges as `T`, and has `UnsafeCell`s at the
240-
// same byte offsets as `T`.
247+
// single `T` field. Thus, `Unalign<T>` has the same size as `T`.
241248
//
242249
// See inline comments for other safety justifications.
243250
unsafe impl<T, I: Invariants> TransparentWrapper<I> for Unalign<T> {
244251
type Inner = T;
245252

253+
// SAFETY: `Unalign<T>` is a `#[repr(C, packed)]` type wrapping a single `T`
254+
// field, and so has `UnsafeCell`s at the same byte ranges as `Inner = T`,
255+
// and `UnsafeCell`s at the same byte offsets as `T`.
256+
type UnsafeCellVariance = Covariant;
257+
246258
// SAFETY: Since `Unalign<T>` is `repr(packed)`, it has the alignment 1
247259
// regardless of `T`'s alignment. Thus, an aligned pointer to `Unalign<T>`
248260
// is not necessarily an aligned pointer to `T`.
@@ -291,8 +303,19 @@ macro_rules! unsafe_impl_transparent_wrapper_for_atomic {
291303
// native counterpart, respectively. Per [1], `$atomic` and `$native`
292304
// have the same size.
293305
//
294-
// It is "obvious" that each atomic type contains a single `UnsafeCell`
295-
// that covers all bytes of the type, but we can also prove it:
306+
// [1] TODO(#896), TODO(https://github.com/rust-lang/rust/pull/121943):
307+
// Cite docs once they've landed.
308+
$(#[$attr])*
309+
unsafe impl<$tyvar, I: Invariants> TransparentWrapper<I> for $atomic {
310+
unsafe_impl_transparent_wrapper_for_atomic!(@inner $atomic [$native]);
311+
}
312+
};
313+
(@inner $atomic:ty [$native:ty]) => {
314+
type Inner = UnsafeCell<$native>;
315+
316+
// SAFETY: It is "obvious" that each atomic type contains a single
317+
// `UnsafeCell` that covers all bytes of the type, but we can also prove
318+
// it:
296319
// - Since `$atomic` provides an API which permits loading and storing
297320
// values of type `$native` via a `&self` (shared) reference, *some*
298321
// interior mutation must be happening, and interior mutation can only
@@ -311,18 +334,9 @@ macro_rules! unsafe_impl_transparent_wrapper_for_atomic {
311334
// set `type Inner = UnsafeCell<$native>`. Thus, `Self` and
312335
// `Self::Inner` have `UnsafeCell`s covering the same byte ranges.
313336
//
314-
// See inline comments for safety requirements regarding invariant
315-
// variance.
316-
//
317337
// [1] TODO(#896), TODO(https://github.com/rust-lang/rust/pull/121943):
318338
// Cite docs once they've landed.
319-
$(#[$attr])*
320-
unsafe impl<$tyvar, I: Invariants> TransparentWrapper<I> for $atomic {
321-
unsafe_impl_transparent_wrapper_for_atomic!(@inner $atomic [$native]);
322-
}
323-
};
324-
(@inner $atomic:ty [$native:ty]) => {
325-
type Inner = UnsafeCell<$native>;
339+
type UnsafeCellVariance = Covariant;
326340

327341
// SAFETY: No safety justification is required for an invariant
328342
// variance.

0 commit comments

Comments
 (0)