Skip to content

Commit f57512f

Browse files
committed
Enforce C,packed, not just packed, on ULE types (unicode-org#5049)
Fixes unicode-org#5039 Caused by rust-lang/rust#125360. We were assuming that `packed` meant `C, packed` already. This is an assumption I've seen throughout the Rust ecosystem so there may be reasons to revert.
1 parent 21e7a0b commit f57512f

File tree

13 files changed

+53
-29
lines changed

13 files changed

+53
-29
lines changed

components/calendar/src/provider/chinese_based.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ impl<'data> ChineseBasedCacheV1<'data> {
143143
derive(databake::Bake),
144144
databake(path = icu_calendar::provider),
145145
)]
146-
#[repr(packed)]
146+
#[repr(C, packed)]
147147
pub struct PackedChineseBasedYearInfo(pub u8, pub u8, pub u8);
148148

149149
impl PackedChineseBasedYearInfo {

components/calendar/src/provider/islamic.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ impl<'data> IslamicCacheV1<'data> {
156156
databake(path = icu_calendar::provider),
157157
)]
158158
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
159-
#[repr(packed)]
159+
#[repr(C, packed)]
160160
pub struct PackedIslamicYearInfo(pub u8, pub u8);
161161

162162
impl fmt::Debug for PackedIslamicYearInfo {

components/casemap/src/provider/exceptions_builder.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ impl ExceptionHeader {
7171
/// In this struct the RESERVED bit is still allowed to be set, and it will produce a different
7272
/// exception header, but it will not have any other effects.
7373
#[derive(Copy, Clone, PartialEq, Eq, ULE)]
74-
#[repr(packed)]
74+
#[repr(C, packed)]
7575
pub struct ExceptionHeaderULE {
7676
slot_presence: SlotPresence,
7777
bits: ExceptionBitsULE,

components/properties/src/provider/bidi_data.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ pub enum CheckedBidiPairedBracketType {
156156
#[doc(hidden)]
157157
/// needed for datagen but not intended for users
158158
#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
159-
#[repr(packed)]
159+
#[repr(C, packed)]
160160
pub struct MirroredPairedBracketDataULE([u8; 3]);
161161

162162
// Safety (based on the safety checklist on the ULE trait):

utils/zerovec/derive/examples/derives.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use zerovec::ule::AsULE;
66
use zerovec::ule::EncodeAsVarULE;
77
use zerovec::*;
88

9-
#[repr(packed)]
9+
#[repr(C, packed)]
1010
#[derive(ule::ULE, Copy, Clone)]
1111
pub struct FooULE {
1212
a: u8,
@@ -40,7 +40,7 @@ impl AsULE for Foo {
4040
}
4141
}
4242

43-
#[repr(packed)]
43+
#[repr(C, packed)]
4444
#[derive(ule::VarULE)]
4545
pub struct RelationULE {
4646
/// This maps to (AndOr, Polarity, Operand),

utils/zerovec/derive/src/make_ule.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ fn make_ule_enum_impl(
8383
attrs: ZeroVecAttrs,
8484
) -> TokenStream2 {
8585
// We could support more int reprs in the future if needed
86-
if !utils::has_valid_repr(&input.attrs, |r| r == "u8") {
86+
if !utils::ReprInfo::compute(&input.attrs).u8 {
8787
return Error::new(
8888
input.span(),
8989
"#[make_ule] can only be applied to #[repr(u8)] enums",

utils/zerovec/derive/src/ule.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ use syn::spanned::Spanned;
1010
use syn::{Data, DeriveInput, Error};
1111

1212
pub fn derive_impl(input: &DeriveInput) -> TokenStream2 {
13-
if !utils::has_valid_repr(&input.attrs, |r| r == "packed" || r == "transparent") {
13+
if !utils::ReprInfo::compute(&input.attrs).cpacked_or_transparent() {
1414
return Error::new(
1515
input.span(),
16-
"derive(ULE) must be applied to a #[repr(packed)] or #[repr(transparent)] type",
16+
"derive(ULE) must be applied to a #[repr(C, packed)] or #[repr(transparent)] type",
1717
)
1818
.to_compile_error();
1919
}

utils/zerovec/derive/src/utils.rs

+33-9
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,38 @@ use syn::punctuated::Punctuated;
1111
use syn::spanned::Spanned;
1212
use syn::{Attribute, Error, Field, Fields, Ident, Index, Result, Token};
1313

14-
// Check that there are repr attributes satisfying the given predicate
15-
pub fn has_valid_repr(attrs: &[Attribute], predicate: impl Fn(&Ident) -> bool + Copy) -> bool {
16-
attrs.iter().filter(|a| a.path().is_ident("repr")).any(|a| {
17-
a.parse_args::<IdentListAttribute>()
18-
.ok()
19-
.and_then(|s| s.idents.iter().find(|s| predicate(s)).map(|_| ()))
20-
.is_some()
21-
})
14+
#[derive(Default)]
15+
pub struct ReprInfo {
16+
pub c: bool,
17+
pub transparent: bool,
18+
pub u8: bool,
19+
pub packed: bool,
20+
}
21+
22+
impl ReprInfo {
23+
pub fn compute(attrs: &[Attribute]) -> Self {
24+
let mut info = ReprInfo::default();
25+
for attr in attrs.iter().filter(|a| a.path().is_ident("repr")) {
26+
if let Ok(pieces) = attr.parse_args::<IdentListAttribute>() {
27+
for piece in pieces.idents.iter() {
28+
if piece == "C" || piece == "c" {
29+
info.c = true;
30+
} else if piece == "transparent" {
31+
info.transparent = true;
32+
} else if piece == "packed" {
33+
info.packed = true;
34+
} else if piece == "u8" {
35+
info.u8 = true;
36+
}
37+
}
38+
}
39+
}
40+
info
41+
}
42+
43+
pub fn cpacked_or_transparent(self) -> bool {
44+
(self.c && self.packed) || self.transparent
45+
}
2246
}
2347

2448
// An attribute that is a list of idents
@@ -60,7 +84,7 @@ pub fn repr_for(f: &Fields) -> TokenStream2 {
6084
if f.len() == 1 {
6185
quote!(transparent)
6286
} else {
63-
quote!(packed)
87+
quote!(C, packed)
6488
}
6589
}
6690

utils/zerovec/derive/src/varule.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ pub fn derive_impl(
1515
input: &DeriveInput,
1616
custom_varule_validator: Option<TokenStream2>,
1717
) -> TokenStream2 {
18-
if !utils::has_valid_repr(&input.attrs, |r| r == "packed" || r == "transparent") {
18+
if !utils::ReprInfo::compute(&input.attrs).cpacked_or_transparent() {
1919
return Error::new(
2020
input.span(),
21-
"derive(VarULE) must be applied to a #[repr(packed)] or #[repr(transparent)] type",
21+
"derive(VarULE) must be applied to a #[repr(C, packed)] or #[repr(transparent)] type",
2222
)
2323
.to_compile_error();
2424
}

utils/zerovec/src/flexzerovec/slice.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use core::ops::Range;
1313
const USIZE_WIDTH: usize = mem::size_of::<usize>();
1414

1515
/// A zero-copy "slice" that efficiently represents `[usize]`.
16-
#[repr(packed)]
16+
#[repr(C, packed)]
1717
pub struct FlexZeroSlice {
1818
// Hard Invariant: 1 <= width <= USIZE_WIDTH (which is target_pointer_width)
1919
// Soft Invariant: width == the width of the largest element

utils/zerovec/src/ule/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ use core::{mem, slice};
6161
/// 6. Acknowledge the following note about the equality invariant.
6262
///
6363
/// If the ULE type is a struct only containing other ULE types (or other types which satisfy invariants 1 and 2,
64-
/// like `[u8; N]`), invariants 1 and 2 can be achieved via `#[repr(packed)]` or `#[repr(transparent)]`.
64+
/// like `[u8; N]`), invariants 1 and 2 can be achieved via `#[repr(C, packed)]` or `#[repr(transparent)]`.
6565
///
6666
/// # Equality invariant
6767
///
@@ -271,7 +271,7 @@ where
271271
/// 7. Acknowledge the following note about the equality invariant.
272272
///
273273
/// If the ULE type is a struct only containing other ULE/VarULE types (or other types which satisfy invariants 1 and 2,
274-
/// like `[u8; N]`), invariants 1 and 2 can be achieved via `#[repr(packed)]` or `#[repr(transparent)]`.
274+
/// like `[u8; N]`), invariants 1 and 2 can be achieved via `#[repr(C, packed)]` or `#[repr(transparent)]`.
275275
///
276276
/// # Equality invariant
277277
///

utils/zerovec/src/ule/option.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use core::mem::{self, MaybeUninit};
2828
// Invariants:
2929
// The MaybeUninit is zeroed when None (bool = false),
3030
// and is valid when Some (bool = true)
31-
#[repr(packed)]
31+
#[repr(C, packed)]
3232
pub struct OptionULE<U>(bool, MaybeUninit<U>);
3333

3434
impl<U: Copy> OptionULE<U> {
@@ -62,11 +62,11 @@ impl<U: Copy + core::fmt::Debug> core::fmt::Debug for OptionULE<U> {
6262

6363
// Safety (based on the safety checklist on the ULE trait):
6464
// 1. OptionULE does not include any uninitialized or padding bytes.
65-
// (achieved by `#[repr(packed)]` on a struct containing only ULE fields,
65+
// (achieved by `#[repr(C, packed)]` on a struct containing only ULE fields,
6666
// in the context of this impl. The MaybeUninit is valid for all byte sequences, and we only generate
6767
/// zeroed or valid-T byte sequences to fill it)
6868
// 2. OptionULE is aligned to 1 byte.
69-
// (achieved by `#[repr(packed)]` on a struct containing only ULE fields, in the context of this impl)
69+
// (achieved by `#[repr(C, packed)]` on a struct containing only ULE fields, in the context of this impl)
7070
// 3. The impl of validate_byte_slice() returns an error if any byte is not valid.
7171
// 4. The impl of validate_byte_slice() returns an error if there are extra bytes.
7272
// 5. The other ULE methods use the default impl.

utils/zerovec/src/ule/tuple.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,15 @@ use core::mem;
3030
macro_rules! tuple_ule {
3131
($name:ident, $len:literal, [ $($t:ident $i:tt),+ ]) => {
3232
#[doc = concat!("ULE type for tuples with ", $len, " elements.")]
33-
#[repr(packed)]
33+
#[repr(C, packed)]
3434
#[allow(clippy::exhaustive_structs)] // stable
3535
pub struct $name<$($t),+>($(pub $t),+);
3636

3737
// Safety (based on the safety checklist on the ULE trait):
3838
// 1. TupleULE does not include any uninitialized or padding bytes.
39-
// (achieved by `#[repr(packed)]` on a struct containing only ULE fields)
39+
// (achieved by `#[repr(C, packed)]` on a struct containing only ULE fields)
4040
// 2. TupleULE is aligned to 1 byte.
41-
// (achieved by `#[repr(packed)]` on a struct containing only ULE fields)
41+
// (achieved by `#[repr(C, packed)]` on a struct containing only ULE fields)
4242
// 3. The impl of validate_byte_slice() returns an error if any byte is not valid.
4343
// 4. The impl of validate_byte_slice() returns an error if there are extra bytes.
4444
// 5. The other ULE methods use the default impl.

0 commit comments

Comments
 (0)