Skip to content

Commit cc0ce21

Browse files
committed
poc packed wrapper
1 parent 99fb5fd commit cc0ce21

File tree

5 files changed

+64
-38
lines changed

5 files changed

+64
-38
lines changed

src/codegen/mod.rs

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2013,34 +2013,32 @@ impl CodeGenerator for CompInfo {
20132013
attributes.push(attributes::doc(comment));
20142014
}
20152015

2016-
let explicit_align = if ctx.options().rust_features().repr_align {
2017-
explicit_align
2018-
} else {
2019-
None
2020-
};
2016+
let mut needs_packed_wrapper = false;
20212017

20222018
// We can't specify both packed(N) and align(N), but the packed()
20232019
// should be redundant in this case.
2024-
if packed && !is_opaque && explicit_align.is_none() {
2020+
if packed && !is_opaque {
20252021
let n = layout.map_or(1, |l| l.align);
20262022
assert!(ctx.options().rust_features().repr_packed_n || n == 1);
2027-
let packed_repr = if n == 1 {
2023+
if explicit_align.is_some() {
2024+
needs_packed_wrapper = true;
2025+
}
2026+
let packed_repr = if n == 1 || needs_packed_wrapper {
20282027
"packed".to_string()
20292028
} else {
20302029
format!("packed({})", n)
20312030
};
20322031
attributes.push(attributes::repr_list(&["C", &packed_repr]));
20332032
} else {
20342033
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-
});
2034+
if let Some(explicit) = explicit_align {
2035+
// Ensure that the struct has the correct alignment even in
2036+
// presence of alignas.
2037+
let explicit = helpers::ast_ty::int_expr(explicit as i64);
2038+
attributes.push(quote! {
2039+
#[repr(align(#explicit))]
2040+
});
2041+
}
20442042
}
20452043

20462044
let derivable_traits = derives_of_item(item, ctx, packed);
@@ -2093,15 +2091,21 @@ impl CodeGenerator for CompInfo {
20932091
attributes.push(attributes::must_use());
20942092
}
20952093

2094+
let layout_ident = if needs_packed_wrapper {
2095+
ctx.rust_ident(canonical_name.to_owned() + "__packed")
2096+
} else {
2097+
canonical_ident.clone()
2098+
};
2099+
20962100
let mut tokens = if is_union && struct_layout.is_rust_union() {
20972101
quote! {
20982102
#( #attributes )*
2099-
pub union #canonical_ident
2103+
pub union #layout_ident
21002104
}
21012105
} else {
21022106
quote! {
21032107
#( #attributes )*
2104-
pub struct #canonical_ident
2108+
pub struct #layout_ident
21052109
}
21062110
};
21072111

@@ -2112,6 +2116,16 @@ impl CodeGenerator for CompInfo {
21122116
});
21132117
result.push(tokens);
21142118

2119+
if needs_packed_wrapper {
2120+
let attributes = attributes::derives(&derives);
2121+
let align = proc_macro2::TokenStream::from_str(&explicit_align.unwrap().to_string()).unwrap();
2122+
result.push(quote! {
2123+
#attributes
2124+
#[repr(C, align(#align))]
2125+
pub struct #canonical_ident(#layout_ident);
2126+
});
2127+
}
2128+
21152129
// Generate the inner types and all that stuff.
21162130
//
21172131
// TODO: In the future we might want to be smart, and use nested
@@ -2211,12 +2225,17 @@ impl CodeGenerator for CompInfo {
22112225
let uninit_decl = if !check_field_offset.is_empty() {
22122226
// FIXME: When MSRV >= 1.59.0, we can use
22132227
// > const PTR: *const #canonical_ident = ::#prefix::mem::MaybeUninit::uninit().as_ptr();
2228+
let layout_cast = if needs_packed_wrapper {
2229+
Some(quote!(as *const #layout_ident))
2230+
} else {
2231+
None
2232+
};
22142233
Some(quote! {
22152234
// Use a shared MaybeUninit so that rustc with
22162235
// opt-level=0 doesn't take too much stack space,
22172236
// see #2218.
22182237
const UNINIT: ::#prefix::mem::MaybeUninit<#canonical_ident> = ::#prefix::mem::MaybeUninit::uninit();
2219-
let ptr = UNINIT.as_ptr();
2238+
let ptr = UNINIT.as_ptr()#layout_cast;
22202239
})
22212240
} else {
22222241
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/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)