Skip to content

Commit 2563db5

Browse files
committed
[derive] Allow TryFromBytes on non-Immutable unions
Makes progress on #5 Closes #1831 Closes #1832 gherrit-pr-id: G27dd847426e3572e87b20bd64642c9fcb0e51ec8
1 parent 21a1122 commit 2563db5

4 files changed

Lines changed: 41 additions & 18 deletions

File tree

zerocopy-derive/src/lib.rs

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -922,16 +922,14 @@ fn derive_try_from_bytes_struct(
922922
}
923923

924924
/// A union is `TryFromBytes` if:
925-
/// - all of its fields are `TryFromBytes` and `Immutable`
925+
/// - all of its fields are `TryFromBytes`
926926
fn derive_try_from_bytes_union(
927927
ast: &DeriveInput,
928928
unn: &DataUnion,
929929
top_level: Trait,
930930
zerocopy_crate: &Path,
931931
) -> TokenStream {
932-
// FIXME(#5): Remove the `Immutable` bound.
933-
let field_type_trait_bounds =
934-
FieldBounds::All(&[TraitBound::Slf, TraitBound::Other(Trait::Immutable)]);
932+
let field_type_trait_bounds = FieldBounds::All(&[TraitBound::Slf]);
935933
let extras =
936934
try_gen_trivial_is_bit_valid(ast, top_level, zerocopy_crate).unwrap_or_else(|| {
937935
let fields = unn.fields();
@@ -950,10 +948,9 @@ fn derive_try_from_bytes_union(
950948

951949
false #(|| {
952950
// SAFETY:
953-
// - Since `Self: Immutable` is enforced by
954-
// `self_type_trait_bounds`, neither `*slf` nor the
955-
// returned pointer's referent contain any
956-
// `UnsafeCell`s
951+
// - Since `ReadOnly<Self>: Immutable` unconditionally,
952+
// neither `*slf` nor the returned pointer's referent
953+
// permit interior mutation.
957954
// - Both source and destination validity are
958955
// `Initialized`, which is always a sound
959956
// transmutation.
@@ -1250,16 +1247,13 @@ fn derive_from_zeros_enum(
12501247
}
12511248

12521249
/// Unions are `FromZeros` if
1253-
/// - all fields are `FromZeros` and `Immutable`
1250+
/// - all fields are `FromZeros`
12541251
fn derive_from_zeros_union(
12551252
ast: &DeriveInput,
12561253
unn: &DataUnion,
12571254
zerocopy_crate: &Path,
12581255
) -> TokenStream {
1259-
// FIXME(#5): Remove the `Immutable` bound. It's only necessary for
1260-
// compatibility with `derive(TryFromBytes)` on unions; not for soundness.
1261-
let field_type_trait_bounds =
1262-
FieldBounds::All(&[TraitBound::Slf, TraitBound::Other(Trait::Immutable)]);
1256+
let field_type_trait_bounds = FieldBounds::All(&[TraitBound::Slf]);
12631257
ImplBlockBuilder::new(ast, unn, Trait::FromZeros, field_type_trait_bounds, zerocopy_crate)
12641258
.build()
12651259
}
@@ -1330,16 +1324,13 @@ fn enum_size_from_repr(repr: &EnumRepr) -> Result<usize, Error> {
13301324
}
13311325

13321326
/// Unions are `FromBytes` if
1333-
/// - all fields are `FromBytes` and `Immutable`
1327+
/// - all fields are `FromBytes`
13341328
fn derive_from_bytes_union(
13351329
ast: &DeriveInput,
13361330
unn: &DataUnion,
13371331
zerocopy_crate: &Path,
13381332
) -> TokenStream {
1339-
// FIXME(#5): Remove the `Immutable` bound. It's only necessary for
1340-
// compatibility with `derive(TryFromBytes)` on unions; not for soundness.
1341-
let field_type_trait_bounds =
1342-
FieldBounds::All(&[TraitBound::Slf, TraitBound::Other(Trait::Immutable)]);
1333+
let field_type_trait_bounds = FieldBounds::All(&[TraitBound::Slf]);
13431334
ImplBlockBuilder::new(ast, unn, Trait::FromBytes, field_type_trait_bounds, zerocopy_crate)
13441335
.build()
13451336
}

zerocopy-derive/tests/union_from_bytes.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,12 @@ where
7272

7373
util_assert_impl_all!(WithParams<'static, 'static, u8, 42>: imp::FromBytes);
7474
test_trivial_is_bit_valid!(WithParams<'static, 'static, u8, 42> => test_with_params_trivial_is_bit_valid);
75+
76+
#[derive(imp::FromBytes)]
77+
#[repr(C)]
78+
union UnsafeCellUnion {
79+
a: imp::ManuallyDrop<imp::UnsafeCell<u8>>,
80+
}
81+
82+
util_assert_impl_all!(UnsafeCellUnion: imp::FromBytes);
83+
test_trivial_is_bit_valid!(UnsafeCellUnion => test_unsafe_cell_union_trivial_is_bit_valid);

zerocopy-derive/tests/union_from_zeros.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,11 @@ where
6767
}
6868

6969
util_assert_impl_all!(WithParams<'static, 'static, u8, 42>: imp::FromZeros);
70+
71+
#[derive(imp::FromZeros)]
72+
#[repr(C)]
73+
union UnsafeCellUnion {
74+
a: imp::ManuallyDrop<imp::UnsafeCell<u8>>,
75+
}
76+
77+
util_assert_impl_all!(UnsafeCellUnion: imp::FromZeros);

zerocopy-derive/tests/union_try_from_bytes.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,18 @@ struct A;
114114
union B {
115115
a: A,
116116
}
117+
118+
#[derive(imp::TryFromBytes)]
119+
#[repr(C)]
120+
union UnsafeCellUnion {
121+
a: imp::ManuallyDrop<imp::UnsafeCell<bool>>,
122+
}
123+
124+
util_assert_impl_all!(UnsafeCellUnion: imp::TryFromBytes);
125+
126+
#[test]
127+
fn unsafe_cell_union() {
128+
crate::util::test_is_bit_valid::<UnsafeCellUnion>([0u8], true);
129+
crate::util::test_is_bit_valid::<UnsafeCellUnion>([1u8], true);
130+
crate::util::test_is_bit_valid::<UnsafeCellUnion>([2u8], false);
131+
}

0 commit comments

Comments
 (0)