From 0e2d977499f9cbec3eaa48061a08fd08bc72aba2 Mon Sep 17 00:00:00 2001 From: Vincent Esche Date: Fri, 3 Aug 2018 02:13:14 +0200 Subject: [PATCH] Added support for `#[repr(transparent)]` --- src/bindgen/ir/enumeration.rs | 2 ++ src/bindgen/ir/repr.rs | 16 +++++++++-- src/bindgen/ir/structure.rs | 31 ++++++++++++++++---- tests/expectations/both/transparent.c | 24 ++++++++++++++++ tests/expectations/tag/transparent.c | 24 ++++++++++++++++ tests/expectations/transparent.c | 24 ++++++++++++++++ tests/expectations/transparent.cpp | 29 +++++++++++++++++++ tests/rust/transparent.rs | 41 +++++++++++++++++++++++++++ 8 files changed, 183 insertions(+), 8 deletions(-) create mode 100644 tests/expectations/both/transparent.c create mode 100644 tests/expectations/tag/transparent.c create mode 100644 tests/expectations/transparent.c create mode 100644 tests/expectations/transparent.cpp create mode 100644 tests/rust/transparent.rs diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index 70180410a..e3be0fd01 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.rs @@ -87,6 +87,7 @@ impl EnumVariant { generic_params: GenericParams::default(), fields: parse_fields(is_tagged, &fields.named)?, is_tagged, + is_transparent: false, tuple_struct: false, cfg: Cfg::append(mod_cfg, Cfg::load(&variant.attrs)), annotations: AnnotationSet::load(&variant.attrs)?, @@ -97,6 +98,7 @@ impl EnumVariant { generic_params: GenericParams::default(), fields: parse_fields(is_tagged, &fields.unnamed)?, is_tagged, + is_transparent: false, tuple_struct: true, cfg: Cfg::append(mod_cfg, Cfg::load(&variant.attrs)), annotations: AnnotationSet::load(&variant.attrs)?, diff --git a/src/bindgen/ir/repr.rs b/src/bindgen/ir/repr.rs index 01f668e6a..0a72bcd85 100644 --- a/src/bindgen/ir/repr.rs +++ b/src/bindgen/ir/repr.rs @@ -4,10 +4,11 @@ use syn; -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum ReprStyle { Rust, C, + Transparent, } impl Default for ReprStyle { @@ -16,7 +17,7 @@ impl Default for ReprStyle { } } -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum ReprType { U8, U16, @@ -28,7 +29,7 @@ pub enum ReprType { ISize, } -#[derive(Debug, Copy, Clone, PartialEq, Default)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)] pub struct Repr { pub style: ReprStyle, pub ty: Option, @@ -40,6 +41,11 @@ impl Repr { ty: None, }; + pub const TRANSPARENT: Self = Repr { + style: ReprStyle::Transparent, + ty: None, + }; + pub const RUST: Self = Repr { style: ReprStyle::Rust, ty: None, @@ -82,6 +88,10 @@ impl Repr { repr.style = ReprStyle::C; continue; } + "transparent" => { + repr.style = ReprStyle::Transparent; + continue; + } _ => { return Err(format!("Unsupported #[repr({})].", id)); } diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index a8c346ec3..f8cbb35d7 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -11,7 +11,7 @@ use bindgen::declarationtyperesolver::DeclarationTypeResolver; use bindgen::dependencies::Dependencies; use bindgen::ir::{ AnnotationSet, Cfg, ConditionWrite, Documentation, GenericParams, Item, ItemContainer, Repr, - ToCondition, Type, + ToCondition, Type, Typedef, }; use bindgen::library::Library; use bindgen::mangle; @@ -26,6 +26,7 @@ pub struct Struct { pub generic_params: GenericParams, pub fields: Vec<(String, Type, Documentation)>, pub is_tagged: bool, + pub is_transparent: bool, pub tuple_struct: bool, pub cfg: Option, pub annotations: AnnotationSet, @@ -39,9 +40,13 @@ impl Struct { } pub fn load(item: &syn::ItemStruct, mod_cfg: &Option) -> Result { - if Repr::load(&item.attrs)? != Repr::C { - return Err("Struct is not marked #[repr(C)].".to_owned()); - } + let is_transparent = match Repr::load(&item.attrs)? { + Repr::C => false, + Repr::TRANSPARENT => true, + _ => { + return Err("Struct is not marked #[repr(C)] or #[repr(transparent)].".to_owned()); + } + }; let (fields, tuple_struct) = match &item.fields { &syn::Fields::Unit => (Vec::new(), false), @@ -70,6 +75,7 @@ impl Struct { generic_params: GenericParams::new(&item.generics), fields: fields, is_tagged: false, + is_transparent: is_transparent, tuple_struct: tuple_struct, cfg: Cfg::append(mod_cfg, Cfg::load(&item.attrs)), annotations: AnnotationSet::load(&item.attrs)?, @@ -128,7 +134,9 @@ impl Item for Struct { } fn collect_declaration_types(&self, resolver: &mut DeclarationTypeResolver) { - resolver.add_struct(&self.name); + if !self.is_transparent { + resolver.add_struct(&self.name); + } } fn resolve_declaration_types(&mut self, resolver: &DeclarationTypeResolver) { @@ -225,6 +233,7 @@ impl Item for Struct { .map(|x| (x.0.clone(), x.1.specialize(&mappings), x.2.clone())) .collect(), is_tagged: self.is_tagged, + is_transparent: self.is_transparent, tuple_struct: self.tuple_struct, cfg: self.cfg.clone(), annotations: self.annotations.clone(), @@ -240,6 +249,18 @@ impl Item for Struct { impl Source for Struct { fn write(&self, config: &Config, out: &mut SourceWriter) { + if self.is_transparent { + let typedef = Typedef { + name: self.name.clone(), + generic_params: self.generic_params.clone(), + aliased: self.fields[0].1.clone(), + cfg: self.cfg.clone(), + annotations: self.annotations.clone(), + documentation: self.documentation.clone(), + }; + return typedef.write(config, out); + } + let condition = (&self.cfg).to_condition(config); condition.write_before(config, out); diff --git a/tests/expectations/both/transparent.c b/tests/expectations/both/transparent.c new file mode 100644 index 000000000..b584ce70a --- /dev/null +++ b/tests/expectations/both/transparent.c @@ -0,0 +1,24 @@ +#include +#include +#include + +typedef struct DummyStruct DummyStruct; + +typedef DummyStruct TransparentComplexWrappingStructTuple; + +typedef uint32_t TransparentPrimitiveWrappingStructTuple; + +typedef DummyStruct TransparentComplexWrappingStructure; + +typedef uint32_t TransparentPrimitiveWrappingStructure; + +typedef DummyStruct TransparentComplexWrapper_i32; + +typedef uint32_t TransparentPrimitiveWrapper_i32; + +void root(TransparentComplexWrappingStructTuple a, + TransparentPrimitiveWrappingStructTuple b, + TransparentComplexWrappingStructure c, + TransparentPrimitiveWrappingStructure d, + TransparentComplexWrapper_i32 e, + TransparentPrimitiveWrapper_i32 f); diff --git a/tests/expectations/tag/transparent.c b/tests/expectations/tag/transparent.c new file mode 100644 index 000000000..98d85ee75 --- /dev/null +++ b/tests/expectations/tag/transparent.c @@ -0,0 +1,24 @@ +#include +#include +#include + +struct DummyStruct; + +typedef struct DummyStruct TransparentComplexWrappingStructTuple; + +typedef uint32_t TransparentPrimitiveWrappingStructTuple; + +typedef struct DummyStruct TransparentComplexWrappingStructure; + +typedef uint32_t TransparentPrimitiveWrappingStructure; + +typedef struct DummyStruct TransparentComplexWrapper_i32; + +typedef uint32_t TransparentPrimitiveWrapper_i32; + +void root(TransparentComplexWrappingStructTuple a, + TransparentPrimitiveWrappingStructTuple b, + TransparentComplexWrappingStructure c, + TransparentPrimitiveWrappingStructure d, + TransparentComplexWrapper_i32 e, + TransparentPrimitiveWrapper_i32 f); diff --git a/tests/expectations/transparent.c b/tests/expectations/transparent.c new file mode 100644 index 000000000..b584ce70a --- /dev/null +++ b/tests/expectations/transparent.c @@ -0,0 +1,24 @@ +#include +#include +#include + +typedef struct DummyStruct DummyStruct; + +typedef DummyStruct TransparentComplexWrappingStructTuple; + +typedef uint32_t TransparentPrimitiveWrappingStructTuple; + +typedef DummyStruct TransparentComplexWrappingStructure; + +typedef uint32_t TransparentPrimitiveWrappingStructure; + +typedef DummyStruct TransparentComplexWrapper_i32; + +typedef uint32_t TransparentPrimitiveWrapper_i32; + +void root(TransparentComplexWrappingStructTuple a, + TransparentPrimitiveWrappingStructTuple b, + TransparentComplexWrappingStructure c, + TransparentPrimitiveWrappingStructure d, + TransparentComplexWrapper_i32 e, + TransparentPrimitiveWrapper_i32 f); diff --git a/tests/expectations/transparent.cpp b/tests/expectations/transparent.cpp new file mode 100644 index 000000000..656876a39 --- /dev/null +++ b/tests/expectations/transparent.cpp @@ -0,0 +1,29 @@ +#include +#include + +struct DummyStruct; + +using TransparentComplexWrappingStructTuple = DummyStruct; + +using TransparentPrimitiveWrappingStructTuple = uint32_t; + +using TransparentComplexWrappingStructure = DummyStruct; + +using TransparentPrimitiveWrappingStructure = uint32_t; + +template +using TransparentComplexWrapper = DummyStruct; + +template +using TransparentPrimitiveWrapper = uint32_t; + +extern "C" { + +void root(TransparentComplexWrappingStructTuple a, + TransparentPrimitiveWrappingStructTuple b, + TransparentComplexWrappingStructure c, + TransparentPrimitiveWrappingStructure d, + TransparentComplexWrapper e, + TransparentPrimitiveWrapper f); + +} // extern "C" diff --git a/tests/rust/transparent.rs b/tests/rust/transparent.rs new file mode 100644 index 000000000..ac8338faf --- /dev/null +++ b/tests/rust/transparent.rs @@ -0,0 +1,41 @@ +struct DummyStruct; + +// Transparent struct tuple wrapping a struct. +#[repr(transparent)] +struct TransparentComplexWrappingStructTuple(DummyStruct); + +// Transparent struct tuple wrapping a primitive. +#[repr(transparent)] +struct TransparentPrimitiveWrappingStructTuple(u32); + +// Transparent structure wrapping a struct. +#[repr(transparent)] +struct TransparentComplexWrappingStructure { only_field: DummyStruct } + +// Transparent structure wrapping a primitive. +#[repr(transparent)] +struct TransparentPrimitiveWrappingStructure { only_field: u32 } + +// Transparent struct wrapper with a marker wrapping a struct. +#[repr(transparent)] +struct TransparentComplexWrapper { + only_non_zero_sized_field: DummyStruct, + marker: PhantomData, +} + +// Transparent struct wrapper with a marker wrapping a primitive. +#[repr(transparent)] +struct TransparentPrimitiveWrapper { + only_non_zero_sized_field: u32, + marker: PhantomData, +} + +#[no_mangle] +pub extern "C" fn root( + a: TransparentComplexWrappingStructTuple, + b: TransparentPrimitiveWrappingStructTuple, + c: TransparentComplexWrappingStructure, + d: TransparentPrimitiveWrappingStructure, + e: TransparentComplexWrapper, + f: TransparentPrimitiveWrapper, +) { }