1*5f85604cSMiguel Ojeda // SPDX-License-Identifier: (BSD-2-Clause OR Apache-2.0) OR MIT 2*5f85604cSMiguel Ojeda 3b437b383SMiguel Ojeda use proc_macro2::{Span, TokenStream}; 4b437b383SMiguel Ojeda use syn::{Data, DataEnum, DataStruct, DataUnion, Error}; 5b437b383SMiguel Ojeda 6b437b383SMiguel Ojeda use crate::{ 7b437b383SMiguel Ojeda repr::{EnumRepr, StructUnionRepr}, 8b437b383SMiguel Ojeda util::{Ctx, FieldBounds, ImplBlockBuilder, Trait}, 9b437b383SMiguel Ojeda }; 10b437b383SMiguel Ojeda 11b437b383SMiguel Ojeda pub(crate) fn derive_unaligned(ctx: &Ctx, _top_level: Trait) -> Result<TokenStream, Error> { 12b437b383SMiguel Ojeda match &ctx.ast.data { 13b437b383SMiguel Ojeda Data::Struct(strct) => derive_unaligned_struct(ctx, strct), 14b437b383SMiguel Ojeda Data::Enum(enm) => derive_unaligned_enum(ctx, enm), 15b437b383SMiguel Ojeda Data::Union(unn) => derive_unaligned_union(ctx, unn), 16b437b383SMiguel Ojeda } 17b437b383SMiguel Ojeda } 18b437b383SMiguel Ojeda 19b437b383SMiguel Ojeda /// A struct is `Unaligned` if: 20b437b383SMiguel Ojeda /// - `repr(align)` is no more than 1 and either 21b437b383SMiguel Ojeda /// - `repr(C)` or `repr(transparent)` and 22b437b383SMiguel Ojeda /// - all fields `Unaligned` 23b437b383SMiguel Ojeda /// - `repr(packed)` 24b437b383SMiguel Ojeda fn derive_unaligned_struct(ctx: &Ctx, strct: &DataStruct) -> Result<TokenStream, Error> { 25b437b383SMiguel Ojeda let repr = StructUnionRepr::from_attrs(&ctx.ast.attrs)?; 26b437b383SMiguel Ojeda repr.unaligned_validate_no_align_gt_1()?; 27b437b383SMiguel Ojeda 28b437b383SMiguel Ojeda let field_bounds = if repr.is_packed_1() { 29b437b383SMiguel Ojeda FieldBounds::None 30b437b383SMiguel Ojeda } else if repr.is_c() || repr.is_transparent() { 31b437b383SMiguel Ojeda FieldBounds::ALL_SELF 32b437b383SMiguel Ojeda } else { 33b437b383SMiguel Ojeda return ctx.error_or_skip(Error::new( 34b437b383SMiguel Ojeda Span::call_site(), 35b437b383SMiguel Ojeda "must have #[repr(C)], #[repr(transparent)], or #[repr(packed)] attribute in order to guarantee this type's alignment", 36b437b383SMiguel Ojeda )); 37b437b383SMiguel Ojeda }; 38b437b383SMiguel Ojeda 39b437b383SMiguel Ojeda Ok(ImplBlockBuilder::new(ctx, strct, Trait::Unaligned, field_bounds).build()) 40b437b383SMiguel Ojeda } 41b437b383SMiguel Ojeda 42b437b383SMiguel Ojeda /// An enum is `Unaligned` if: 43b437b383SMiguel Ojeda /// - No `repr(align(N > 1))` 44b437b383SMiguel Ojeda /// - `repr(u8)` or `repr(i8)` 45b437b383SMiguel Ojeda fn derive_unaligned_enum(ctx: &Ctx, enm: &DataEnum) -> Result<TokenStream, Error> { 46b437b383SMiguel Ojeda let repr = EnumRepr::from_attrs(&ctx.ast.attrs)?; 47b437b383SMiguel Ojeda repr.unaligned_validate_no_align_gt_1()?; 48b437b383SMiguel Ojeda 49b437b383SMiguel Ojeda if !repr.is_u8() && !repr.is_i8() { 50b437b383SMiguel Ojeda return ctx.error_or_skip(Error::new( 51b437b383SMiguel Ojeda Span::call_site(), 52b437b383SMiguel Ojeda "must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment", 53b437b383SMiguel Ojeda )); 54b437b383SMiguel Ojeda } 55b437b383SMiguel Ojeda 56b437b383SMiguel Ojeda Ok(ImplBlockBuilder::new(ctx, enm, Trait::Unaligned, FieldBounds::ALL_SELF).build()) 57b437b383SMiguel Ojeda } 58b437b383SMiguel Ojeda 59b437b383SMiguel Ojeda /// Like structs, a union is `Unaligned` if: 60b437b383SMiguel Ojeda /// - `repr(align)` is no more than 1 and either 61b437b383SMiguel Ojeda /// - `repr(C)` or `repr(transparent)` and 62b437b383SMiguel Ojeda /// - all fields `Unaligned` 63b437b383SMiguel Ojeda /// - `repr(packed)` 64b437b383SMiguel Ojeda fn derive_unaligned_union(ctx: &Ctx, unn: &DataUnion) -> Result<TokenStream, Error> { 65b437b383SMiguel Ojeda let repr = StructUnionRepr::from_attrs(&ctx.ast.attrs)?; 66b437b383SMiguel Ojeda repr.unaligned_validate_no_align_gt_1()?; 67b437b383SMiguel Ojeda 68b437b383SMiguel Ojeda let field_type_trait_bounds = if repr.is_packed_1() { 69b437b383SMiguel Ojeda FieldBounds::None 70b437b383SMiguel Ojeda } else if repr.is_c() || repr.is_transparent() { 71b437b383SMiguel Ojeda FieldBounds::ALL_SELF 72b437b383SMiguel Ojeda } else { 73b437b383SMiguel Ojeda return ctx.error_or_skip(Error::new( 74b437b383SMiguel Ojeda Span::call_site(), 75b437b383SMiguel Ojeda "must have #[repr(C)], #[repr(transparent)], or #[repr(packed)] attribute in order to guarantee this type's alignment", 76b437b383SMiguel Ojeda )); 77b437b383SMiguel Ojeda }; 78b437b383SMiguel Ojeda 79b437b383SMiguel Ojeda Ok(ImplBlockBuilder::new(ctx, unn, Trait::Unaligned, field_type_trait_bounds).build()) 80b437b383SMiguel Ojeda } 81