Skip to content

Commit 5875601

Browse files
committed
poc packed wrapper
1 parent 93df584 commit 5875601

File tree

6 files changed

+79
-45
lines changed

6 files changed

+79
-45
lines changed

src/codegen/mod.rs

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2009,38 +2009,35 @@ 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
}
20152016

2016-
let explicit_align = if ctx.options().rust_features().repr_align {
2017-
explicit_align
2018-
} else {
2019-
None
2020-
};
2021-
20222017
// We can't specify both packed(N) and align(N), but the packed()
20232018
// should be redundant in this case.
2024-
if packed && !is_opaque && explicit_align.is_none() {
2019+
if packed && !is_opaque {
20252020
let n = layout.map_or(1, |l| l.align);
20262021
assert!(ctx.options().rust_features().repr_packed_n || n == 1);
2027-
let packed_repr = if n == 1 {
2022+
if explicit_align.is_some() {
2023+
needs_packed_wrapper = true;
2024+
}
2025+
let packed_repr = if n == 1 || needs_packed_wrapper {
20282026
"packed".to_string()
20292027
} else {
20302028
format!("packed({})", n)
20312029
};
20322030
attributes.push(attributes::repr_list(&["C", &packed_repr]));
20332031
} else {
20342032
attributes.push(attributes::repr("C"));
2035-
}
2036-
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-
});
2033+
if let Some(explicit) = explicit_align {
2034+
// Ensure that the struct has the correct alignment even in
2035+
// presence of alignas.
2036+
let explicit = helpers::ast_ty::int_expr(explicit as i64);
2037+
attributes.push(quote! {
2038+
#[repr(align(#explicit))]
2039+
});
2040+
}
20442041
}
20452042

20462043
let derivable_traits = derives_of_item(item, ctx, packed);
@@ -2093,15 +2090,21 @@ impl CodeGenerator for CompInfo {
20932090
attributes.push(attributes::must_use());
20942091
}
20952092

2093+
let layout_ident = if needs_packed_wrapper {
2094+
ctx.rust_ident(canonical_name.to_owned() + "__packed")
2095+
} else {
2096+
canonical_ident.clone()
2097+
};
2098+
20962099
let mut tokens = if is_union && struct_layout.is_rust_union() {
20972100
quote! {
20982101
#( #attributes )*
2099-
pub union #canonical_ident
2102+
pub union #layout_ident
21002103
}
21012104
} else {
21022105
quote! {
21032106
#( #attributes )*
2104-
pub struct #canonical_ident
2107+
pub struct #layout_ident
21052108
}
21062109
};
21072110

@@ -2112,6 +2115,19 @@ impl CodeGenerator for CompInfo {
21122115
});
21132116
result.push(tokens);
21142117

2118+
if needs_packed_wrapper {
2119+
let attributes = attributes::derives(&derives);
2120+
let align = proc_macro2::TokenStream::from_str(
2121+
&explicit_align.unwrap().to_string(),
2122+
)
2123+
.unwrap();
2124+
result.push(quote! {
2125+
#attributes
2126+
#[repr(C, align(#align))]
2127+
pub struct #canonical_ident(#layout_ident);
2128+
});
2129+
}
2130+
21152131
// Generate the inner types and all that stuff.
21162132
//
21172133
// TODO: In the future we might want to be smart, and use nested
@@ -2211,12 +2227,17 @@ impl CodeGenerator for CompInfo {
22112227
let uninit_decl = if !check_field_offset.is_empty() {
22122228
// FIXME: When MSRV >= 1.59.0, we can use
22132229
// > const PTR: *const #canonical_ident = ::#prefix::mem::MaybeUninit::uninit().as_ptr();
2230+
let layout_cast = if needs_packed_wrapper {
2231+
Some(quote!(as *const #layout_ident))
2232+
} else {
2233+
None
2234+
};
22142235
Some(quote! {
22152236
// Use a shared MaybeUninit so that rustc with
22162237
// opt-level=0 doesn't take too much stack space,
22172238
// see #2218.
22182239
const UNINIT: ::#prefix::mem::MaybeUninit<#canonical_ident> = ::#prefix::mem::MaybeUninit::uninit();
2219-
let ptr = UNINIT.as_ptr();
2240+
let ptr = UNINIT.as_ptr()#layout_cast;
22202241
})
22212242
} else {
22222243
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: 7 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/expectations/tests/packed-n-with-padding.rs

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

0 commit comments

Comments
 (0)