Skip to content

Commit

Permalink
Merge pull request #2079 from dtolnay/packedremote
Browse files Browse the repository at this point in the history
Fix unaligned reference warnings on packed remote def
  • Loading branch information
dtolnay authored Aug 23, 2021
2 parents 55fdbea + 54102ee commit dc0c0dc
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 9 deletions.
7 changes: 6 additions & 1 deletion serde_derive/src/de.rs
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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,
}

0 comments on commit dc0c0dc

Please sign in to comment.