Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix unaligned reference warnings on packed remote def #2079

Merged
merged 2 commits into from Aug 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 6 additions & 1 deletion serde_derive/src/de.rs
Expand Up @@ -36,7 +36,7 @@ pub fn expand_derive_deserialize(

let impl_block = if let Some(remote) = cont.attrs.remote() {
let vis = &input.vis;
let used = pretend::pretend_used(&cont);
let used = pretend::pretend_used(&cont, params.is_packed);
quote! {
impl #de_impl_generics #ident #ty_generics #where_clause {
#vis fn deserialize<__D>(__deserializer: __D) -> #serde::__private::Result<#remote #ty_generics, __D::Error>
Expand Down Expand Up @@ -125,6 +125,9 @@ struct Parameters {
/// At least one field has a serde(getter) attribute, implying that the
/// remote type has a private field.
has_getter: bool,

/// Type has a repr(packed) attribute.
is_packed: bool,
}

impl Parameters {
Expand All @@ -137,13 +140,15 @@ impl Parameters {
let borrowed = borrowed_lifetimes(cont);
let generics = build_generics(cont, &borrowed);
let has_getter = cont.data.has_getter();
let is_packed = cont.attrs.is_packed();

Parameters {
local,
this,
generics,
borrowed,
has_getter,
is_packed,
}
}

Expand Down
19 changes: 12 additions & 7 deletions serde_derive/src/pretend.rs
Expand Up @@ -20,8 +20,8 @@ use internals::ast::{Container, Data, Field, Style};
// 8 | enum EnumDef { V }
// | ^
//
pub fn pretend_used(cont: &Container) -> TokenStream {
let pretend_fields = pretend_fields_used(cont);
pub fn pretend_used(cont: &Container, is_packed: bool) -> TokenStream {
let pretend_fields = pretend_fields_used(cont, is_packed);
let pretend_variants = pretend_variants_used(cont);

quote! {
Expand All @@ -48,7 +48,7 @@ pub fn pretend_used(cont: &Container) -> TokenStream {
// The `ref` is important in case the user has written a Drop impl on their
// type. Rust does not allow destructuring a struct or enum that has a Drop
// impl.
fn pretend_fields_used(cont: &Container) -> TokenStream {
fn pretend_fields_used(cont: &Container, is_packed: bool) -> TokenStream {
let type_ident = &cont.ident;
let (_, ty_generics, _) = cont.generics.split_for_impl();

Expand All @@ -58,14 +58,14 @@ fn pretend_fields_used(cont: &Container) -> TokenStream {
.filter_map(|variant| match variant.style {
Style::Struct => {
let variant_ident = &variant.ident;
let pat = struct_pattern(&variant.fields);
let pat = struct_pattern(&variant.fields, is_packed);
Some(quote!(#type_ident::#variant_ident #pat))
}
_ => None,
})
.collect::<Vec<_>>(),
Data::Struct(Style::Struct, fields) => {
let pat = struct_pattern(fields);
let pat = struct_pattern(fields, is_packed);
vec![quote!(#type_ident #pat)]
}
Data::Struct(_, _) => {
Expand Down Expand Up @@ -132,9 +132,14 @@ fn pretend_variants_used(cont: &Container) -> TokenStream {
quote!(#(#cases)*)
}

fn struct_pattern(fields: &[Field]) -> TokenStream {
fn struct_pattern(fields: &[Field], is_packed: bool) -> TokenStream {
let members = fields.iter().map(|field| &field.member);
let placeholders =
(0..fields.len()).map(|i| Ident::new(&format!("__v{}", i), Span::call_site()));
quote!({ #(#members: ref #placeholders),* })
let take_reference = if is_packed {
None
} else {
Some(quote!(ref))
};
quote!({ #(#members: #take_reference #placeholders),* })
}
2 changes: 1 addition & 1 deletion serde_derive/src/ser.rs
Expand Up @@ -30,7 +30,7 @@ pub fn expand_derive_serialize(

let impl_block = if let Some(remote) = cont.attrs.remote() {
let vis = &input.vis;
let used = pretend::pretend_used(&cont);
let used = pretend::pretend_used(&cont, params.is_packed);
quote! {
impl #impl_generics #ident #ty_generics #where_clause {
#vis fn serialize<__S>(__self: &#remote #ty_generics, __serializer: __S) -> #serde::__private::Result<__S::Ok, __S::Error>
Expand Down
16 changes: 16 additions & 0 deletions test_suite/tests/test_gen.rs
Expand Up @@ -846,3 +846,19 @@ where
{
T::deserialize(deserializer)
}

//////////////////////////////////////////////////////////////////////////

#[repr(packed)]
pub struct RemotePacked {
pub a: u8,
pub b: u16,
}

#[derive(Serialize, Deserialize)]
#[repr(packed)]
#[serde(remote = "RemotePacked")]
pub struct RemotePackedDef {
a: u8,
b: u16,
}