Skip to content

Commit 3785a8e

Browse files
committed
poc packed wrapper
1 parent 61f307d commit 3785a8e

File tree

6 files changed

+106
-48
lines changed

6 files changed

+106
-48
lines changed

src/codegen/mod.rs

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2009,32 +2009,39 @@ impl CodeGenerator for CompInfo {
20092009
let mut needs_default_impl = false;
20102010
let mut needs_debug_impl = false;
20112011
let mut needs_partialeq_impl = false;
2012+
let mut needs_packed_wrapper = false;
20122013
if let Some(comment) = item.comment(ctx) {
20132014
attributes.push(attributes::doc(comment));
20142015
}
2016+
2017+
// We can't specify both packed(N) and align(N), but the packed()
2018+
// should be redundant in this case.
20152019
if packed && !is_opaque {
20162020
let n = layout.map_or(1, |l| l.align);
20172021
assert!(ctx.options().rust_features().repr_packed_n || n == 1);
2018-
let packed_repr = if n == 1 {
2022+
if ctx.options().rust_features().repr_align &&
2023+
explicit_align.is_some()
2024+
{
2025+
needs_packed_wrapper = true;
2026+
}
2027+
let packed_repr = if n == 1 || needs_packed_wrapper {
20192028
"packed".to_string()
20202029
} else {
20212030
format!("packed({})", n)
20222031
};
20232032
attributes.push(attributes::repr_list(&["C", &packed_repr]));
20242033
} else {
20252034
attributes.push(attributes::repr("C"));
2026-
}
20272035

2028-
if ctx.options().rust_features().repr_align && !packed {
2029-
// We can't specify both packed(N) and align(N), but the align()
2030-
// should be redundant in this case.
2031-
if let Some(explicit) = explicit_align {
2032-
// Ensure that the struct has the correct alignment even in
2033-
// presence of alignas.
2034-
let explicit = helpers::ast_ty::int_expr(explicit as i64);
2035-
attributes.push(quote! {
2036-
#[repr(align(#explicit))]
2037-
});
2036+
if ctx.options().rust_features().repr_align {
2037+
if let Some(explicit) = explicit_align {
2038+
// Ensure that the struct has the correct alignment even in
2039+
// presence of alignas.
2040+
let explicit = helpers::ast_ty::int_expr(explicit as i64);
2041+
attributes.push(quote! {
2042+
#[repr(align(#explicit))]
2043+
});
2044+
}
20382045
}
20392046
}
20402047

@@ -2088,15 +2095,21 @@ impl CodeGenerator for CompInfo {
20882095
attributes.push(attributes::must_use());
20892096
}
20902097

2098+
let layout_ident = if needs_packed_wrapper {
2099+
ctx.rust_ident(canonical_name.to_owned() + "__packed")
2100+
} else {
2101+
canonical_ident.clone()
2102+
};
2103+
20912104
let mut tokens = if is_union && struct_layout.is_rust_union() {
20922105
quote! {
20932106
#( #attributes )*
2094-
pub union #canonical_ident
2107+
pub union #layout_ident
20952108
}
20962109
} else {
20972110
quote! {
20982111
#( #attributes )*
2099-
pub struct #canonical_ident
2112+
pub struct #layout_ident
21002113
}
21012114
};
21022115

@@ -2107,6 +2120,19 @@ impl CodeGenerator for CompInfo {
21072120
});
21082121
result.push(tokens);
21092122

2123+
if needs_packed_wrapper {
2124+
let attributes = attributes::derives(&derives);
2125+
let align = proc_macro2::TokenStream::from_str(
2126+
&explicit_align.unwrap().to_string(),
2127+
)
2128+
.unwrap();
2129+
result.push(quote! {
2130+
#attributes
2131+
#[repr(C, align(#align))]
2132+
pub struct #canonical_ident(pub #layout_ident);
2133+
});
2134+
}
2135+
21102136
// Generate the inner types and all that stuff.
21112137
//
21122138
// TODO: In the future we might want to be smart, and use nested
@@ -2206,12 +2232,17 @@ impl CodeGenerator for CompInfo {
22062232
let uninit_decl = if !check_field_offset.is_empty() {
22072233
// FIXME: When MSRV >= 1.59.0, we can use
22082234
// > const PTR: *const #canonical_ident = ::#prefix::mem::MaybeUninit::uninit().as_ptr();
2235+
let layout_cast = if needs_packed_wrapper {
2236+
Some(quote!(as *const #layout_ident))
2237+
} else {
2238+
None
2239+
};
22092240
Some(quote! {
22102241
// Use a shared MaybeUninit so that rustc with
22112242
// opt-level=0 doesn't take too much stack space,
22122243
// see #2218.
22132244
const UNINIT: ::#prefix::mem::MaybeUninit<#canonical_ident> = ::#prefix::mem::MaybeUninit::uninit();
2214-
let ptr = UNINIT.as_ptr();
2245+
let ptr = UNINIT.as_ptr()#layout_cast;
22152246
})
22162247
} else {
22172248
None

src/codegen/struct_layout.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ impl<'a> StructLayoutTracker<'a> {
365365
return true;
366366
}
367367

368-
if self.max_field_align >= layout.align {
368+
if !self.is_packed && self.max_field_align >= layout.align {
369369
return false;
370370
}
371371

tests/expectations/tests/issue-537-repr-packed-n.rs

Lines changed: 12 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/expectations/tests/issue-537.rs

Lines changed: 12 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/expectations/tests/packed-align-conflict.rs

Lines changed: 28 additions & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/headers/packed-align-conflict.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1-
struct FndrOpaqueInfo {
2-
char opaque[16];
1+
typedef unsigned char uint8_t;
2+
typedef unsigned short uint16_t;
3+
4+
struct B {
5+
uint8_t a;
6+
uint16_t b;
7+
uint8_t c;
38
} __attribute__((aligned(2), packed));

0 commit comments

Comments
 (0)