diff --git a/src/impls.rs b/src/impls.rs index 02153b86c4..d1344098cf 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -994,19 +994,19 @@ mod tuples { /// /// # Safety /// - /// `impl_tuple!` should be provided name-number pairs, where each number is - /// the ordinal of the preceding type name. + /// `impl_tuple!` should be provided name-validity-number triplets, where + /// each number is the ordinal of the triplet. macro_rules! impl_tuple { // Entry point. - ($($T:ident $I:tt),+ $(,)?) => { + ($($T:ident $V:ident $I:tt),+ $(,)?) => { crate::util::macros::__unsafe(); - impl_tuple!(@all [] [$($T $I)+]); + impl_tuple!(@all [] [$($T $V $I)+]); }; // Build up the set of tuple types (i.e., `(A,)`, `(A, B)`, `(A, B, C)`, // etc.) Trait implementations that do not depend on field index may be // added to this branch. - (@all [$($head_T:ident $head_I:tt)*] [$next_T:ident $next_I:tt $($tail:tt)*]) => { + (@all [$($head_T:ident $head_V:ident $head_I:tt)*] [$next_T:ident $next_V:ident $next_I:tt $($tail:tt)*]) => { // SAFETY: If all fields of the tuple `Self` are `Immutable`, so too is `Self`. unsafe_impl!($($head_T: Immutable,)* $next_T: Immutable => Immutable for ($($head_T,)* $next_T,)); @@ -1023,6 +1023,19 @@ mod tuples { // SAFETY: If all fields in `Self` are `FromBytes`, so too is `Self`. unsafe_impl!($($head_T: FromBytes,)* $next_T: FromBytes => FromBytes for ($($head_T,)* $next_T,)); + // SAFETY: TODO + unsafe impl<$($head_T,)* $next_T> crate::invariant::Validity for ($($head_T,)* $next_T,) + where + $($head_T: crate::invariant::Validity,)* + $next_T: crate::invariant::Validity, + { + const KIND: crate::invariant::ValidityKind = crate::invariant::ValidityKind::Compound(&[ + $($head_T::KIND,)* + $next_T::KIND, + ]); + } + impl<$($head_T,)* $next_T> crate::invariant::sealed::Sealed for ($($head_T,)* $next_T,) {} + // SAFETY: See safety comment on `ProjectToTag`. unsafe impl<$($head_T,)* $next_T> crate::HasTag for ($($head_T,)* $next_T,) { #[inline] @@ -1048,24 +1061,24 @@ mod tuples { // Generate impls that depend on tuple index. impl_tuple!(@variants - [$($head_T $head_I)* $next_T $next_I] + [$($head_T $head_V $head_I)* $next_T $next_V $next_I] [] - [$($head_T $head_I)* $next_T $next_I] + [$($head_T $head_V $head_I)* $next_T $next_V $next_I] ); // Recurse to next tuple size - impl_tuple!(@all [$($head_T $head_I)* $next_T $next_I] [$($tail)*]); + impl_tuple!(@all [$($head_T $head_V $head_I)* $next_T $next_V $next_I] [$($tail)*]); }; - (@all [$($head_T:ident $head_I:tt)*] []) => {}; + (@all [$($head_T:ident $head_V:ident $head_I:tt)*] []) => {}; // Emit trait implementations that depend on field index. (@variants - // The full tuple definition in type–index pairs. - [$($AllT:ident $AllI:tt)+] + // The full tuple definition in type–ident-index triplets. + [$($AllT:ident $AllV:ident $AllI:tt)+] // Types before the current index. - [$($BeforeT:ident)*] + [$($BeforeT:ident $BeforeV:ident)*] // The types and indices at and after the current index. - [$CurrT:ident $CurrI:tt $($AfterT:ident $AfterI:tt)*] + [$CurrT:ident $CurrV:ident $CurrI:tt $($AfterT:ident $AfterV:ident $AfterI:tt)*] ) => { // SAFETY: // - `Self` is a struct (albeit anonymous), so `VARIANT_ID` is @@ -1178,47 +1191,75 @@ mod tuples { type Error = core::convert::Infallible; } + // SAFETY: See comments on items. + unsafe impl crate::ProjectField< + (), + (Aliasing, Alignment, ($($AllV,)+)), + { crate::STRUCT_VARIANT_ID }, + { crate::ident_id!($CurrI)} + > for ($($AllT,)+) + where + Aliasing: crate::invariant::Aliasing, + Alignment: crate::invariant::Alignment, + $($AllV: crate::invariant::Validity,)* + { + #[inline] + fn only_derive_is_allowed_to_implement_this_trait() + where + Self: Sized + {} + + // SAFETY: Tuples are product types whose fields are + // well-aligned, so projection preserves the alignment invariant + // of the outer pointer. The outer pointer's validity is a tuple + // of the validity of its fields, so the validity of the + // projected field is the projected of that validity tuple. + type Invariants = (Aliasing, Alignment, $CurrV); + + // SAFETY: Tuples are product types and so projection is infallible; + type Error = core::convert::Infallible; + } + // Recurse to the next index. - impl_tuple!(@variants [$($AllT $AllI)+] [$($BeforeT)* $CurrT] [$($AfterT $AfterI)*]); + impl_tuple!(@variants [$($AllT $AllV $AllI)+] [$($BeforeT $BeforeV)* $CurrT $CurrV] [$($AfterT $AfterV $AfterI)*]); }; - (@variants [$($AllT:ident $AllI:tt)+] [$($BeforeT:ident)*] []) => {}; + (@variants [$($AllT:ident $AllV:ident $AllI:tt)+] [$($BeforeT:ident $BeforeV:ident)*] []) => {}; } - // SAFETY: `impl_tuple` is provided name-number pairs, where number is the - // ordinal of the name. + // SAFETY: `impl_tuple` is provided name-validity-number triplets, where + // number is the ordinal of the triplet. #[allow(clippy::multiple_unsafe_ops_per_block)] const _: () = unsafe { impl_tuple! { - A 0, - B 1, - C 2, - D 3, - E 4, - F 5, - G 6, - H 7, - I 8, - J 9, - K 10, - L 11, - M 12, - N 13, - O 14, - P 15, - Q 16, - R 17, - S 18, - T 19, - U 20, - V 21, - W 22, - X 23, - Y 24, - Z 25, + A VA 0, + B VB 1, + C VC 2, + D VD 3, + E VE 4, + F VF 5, + G VG 6, + H VH 7, + I VI 8, + J VJ 9, + K VK 10, + L VL 11, + M VM 12, + N VN 13, + O VO 14, + P VP 15, + Q VQ 16, + R VR 17, + S VS 18, + T VT 19, + U VU 20, + V VV 21, + W VW 22, + X VX 23, + Y VY 24, + Z VZ 25, }; }; } - // SIMD support // // Per the Unsafe Code Guidelines Reference [1]: diff --git a/src/lib.rs b/src/lib.rs index 286f294497..23793e3882 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1268,14 +1268,18 @@ where _enum_variant => { use crate::invariant::{Validity, ValidityKind}; match I::Validity::KIND { - // The `Uninit` and `Initialized` validity - // invariants do not depend on the enum's tag. In - // particular, we don't actually care about what - // variant is present – we can treat *any* range of - // uninitialized or initialized memory as containing - // an uninitialized or initialized instance of *any* - // type – the type itself is irrelevant. - ValidityKind::Uninit | ValidityKind::Initialized => true, + // The `Uninit`, `Initialized` and `Compound` + // validity invariants do not depend on the enum's + // tag. In particular, we don't actually care about + // what variant is present – we can treat *any* + // range of uninitialized or initialized memory as + // containing an uninitialized or initialized + // instance of *any* type – the type itself is + // irrelevant. + // TODO: What about compound validity? + ValidityKind::Uninit + | ValidityKind::Initialized + | ValidityKind::Compound(..) => true, // The projectability of an enum field from an // `AsInitialized` or `Valid` state is a dynamic // property of its tag. diff --git a/src/pointer/invariant.rs b/src/pointer/invariant.rs index de5d9cd295..0ce795f260 100644 --- a/src/pointer/invariant.rs +++ b/src/pointer/invariant.rs @@ -64,6 +64,8 @@ pub trait Alignment: Sealed { /// other property of `T`. As a consequence, given `V: Validity`, `T`, and `U` /// where `T` and `U` have the same bit validity, `S(V, T) = S(V, U)`. /// +/// TODO: Document compound validity. +/// /// It is guaranteed that the referent of any `ptr: Ptr` is a member of /// `S(T, V)`. Unsafe code must ensure that this guarantee will be upheld for /// any existing `Ptr`s or any `Ptr`s that that code creates. @@ -100,6 +102,7 @@ pub enum ValidityKind { AsInitialized, Initialized, Valid, + Compound(&'static [ValidityKind]), } /// An [`Aliasing`] invariant which is either [`Shared`] or [`Exclusive`]. @@ -275,7 +278,7 @@ pub enum BecauseExclusive {} pub enum BecauseImmutable {} use sealed::Sealed; -mod sealed { +pub(crate) mod sealed { use super::*; pub trait Sealed {} @@ -291,8 +294,6 @@ mod sealed { impl Sealed for Initialized {} impl Sealed for Valid {} - impl Sealed for (A, AA, V) {} - impl Sealed for BecauseImmutable {} impl Sealed for BecauseExclusive {} }