diff --git a/docs.md b/docs.md index 9abd5d918..8b85de391 100644 --- a/docs.md +++ b/docs.md @@ -107,9 +107,9 @@ You can learn about all of the different repr attributes [by reading Rust's refe * `#[repr(u8, u16, ... etc)]`: give this enum the same layout and ABI as the given integer type * `#[repr(transparent)]`: give this single-field struct the same ABI as its field (useful for newtyping integers but keeping the integer ABI) -cbindgen does not currently support the align or packed reprs. +cbindgen supports the `#[repr(align(N))]` and `#[repr(packed)]` attributes, but currently does not support `#[repr(packed(N))]`. -However it *does* support using `repr(C)`/`repr(u8)` on non-C-like enums (enums with fields). This gives a C-compatible tagged union layout, as [defined by this RFC 2195][really-tagged-unions]. `repr(C)` will give a simpler layout that is perhaps more intuitive, while `repr(u8)` will produce a more compact layout. +cbindgen also supports using `repr(C)`/`repr(u8)` on non-C-like enums (enums with fields). This gives a C-compatible tagged union layout, as [defined by this RFC 2195][really-tagged-unions]. `repr(C)` will give a simpler layout that is perhaps more intuitive, while `repr(u8)` will produce a more compact layout. If you ensure everything has a guaranteed repr, then cbindgen will generate definitions for: @@ -494,8 +494,27 @@ renaming_overrides_prefixing = true void cppMethod() const; """ +[layout] +# A string that should come before the name of any type which has been marked +# as `#[repr(packed)]`. For instance, "__attribute__((packed))" would be a +# reasonable value if targeting gcc/clang. A more portable solution would +# involve emitting the name of a macro which you define in a platform-specific +# way. e.g. "PACKED" +# +# default: `#[repr(packed)]` types will be treated as opaque, since it would +# be unsafe for C callers to use a incorrectly laid-out union. +packed = "PACKED" - +# A string that should come before the name of any type which has been marked +# as `#[repr(align(n))]`. This string must be a function-like macro which takes +# a single argument (the requested alignment, `n`). For instance, a macro +# `#define`d as `ALIGNED(n)` in `header` which translates to +# `__attribute__((aligned(n)))` would be a reasonable value if targeting +# gcc/clang. +# +# default: `#[repr(align(n))]` types will be treated as opaque, since it +# could be unsafe for C callers to use a incorrectly-aligned union. +aligned_n = "ALIGNED" [fn] @@ -546,9 +565,6 @@ must_use = "MUST_USE_FUNC" rename_args = "PascalCase" - - - [struct] # A rule to use to rename struct field names. The renaming assumes the input is # the Rust standard snake_case, however it acccepts all the different rename_args diff --git a/src/bindgen/builder.rs b/src/bindgen/builder.rs index 5d279c90d..cdcf86cc2 100644 --- a/src/bindgen/builder.rs +++ b/src/bindgen/builder.rs @@ -295,7 +295,7 @@ impl Builder { } for x in &self.srcs { - result.extend_with(&parser::parse_src(x, &self.config.macro_expansion)?); + result.extend_with(&parser::parse_src(x, &self.config)?); } if let Some((lib_dir, binding_lib_name)) = self.lib.clone() { @@ -319,17 +319,9 @@ impl Builder { )? }; - result.extend_with(&parser::parse_lib( - cargo, - &self.config.macro_expansion, - &self.config.parse, - )?); + result.extend_with(&parser::parse_lib(cargo, &self.config)?); } else if let Some(cargo) = self.lib_cargo.clone() { - result.extend_with(&parser::parse_lib( - cargo, - &self.config.macro_expansion, - &self.config.parse, - )?); + result.extend_with(&parser::parse_lib(cargo, &self.config)?); } Library::new( diff --git a/src/bindgen/config.rs b/src/bindgen/config.rs index 43765f3cd..70787bff5 100644 --- a/src/bindgen/config.rs +++ b/src/bindgen/config.rs @@ -14,6 +14,7 @@ use toml; use bindgen::ir::annotation::AnnotationSet; use bindgen::ir::path::Path; +use bindgen::ir::repr::ReprAlign; pub use bindgen::rename::RenameRule; pub const VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -245,6 +246,29 @@ impl ExportConfig { } } +/// Settings to apply to generated types with layout modifiers. +#[derive(Debug, Default, Clone, Deserialize)] +#[serde(rename_all = "snake_case")] +#[serde(deny_unknown_fields)] +#[serde(default)] +pub struct LayoutConfig { + /// The way to annotate C types as #[repr(packed)]. + pub packed: Option, + /// The way to annotate C types as #[repr(align(...))]. This is assumed to be a functional + /// macro which takes a single argument (the alignment). + pub aligned_n: Option, +} + +impl LayoutConfig { + pub(crate) fn ensure_safe_to_represent(&self, align: &ReprAlign) -> Result<(), String> { + match (align, &self.packed, &self.aligned_n) { + (ReprAlign::Packed, None, _) => Err("Cannot safely represent #[repr(packed)] type without configured 'packed' annotation.".to_string()), + (ReprAlign::Align(_), _, None) => Err("Cannot safely represent #[repr(aligned(...))] type without configured 'aligned_n' annotation.".to_string()), + _ => Ok(()), + } + } +} + /// Settings to apply to generated functions. #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "snake_case")] @@ -317,7 +341,7 @@ pub struct StructConfig { /// Whether associated constants should be in the body. Only applicable to /// non-transparent structs, and in C++-only. pub associated_constants_in_body: bool, - /// The way to annotation this struct as #[must_use]. + /// The way to annotate this struct as #[must_use]. pub must_use: Option, } @@ -637,6 +661,8 @@ pub struct Config { pub export: ExportConfig, /// The configuration options for macros. pub macro_expansion: MacroExpansionConfig, + /// The configuration options for type layouts. + pub layout: LayoutConfig, /// The configuration options for functions #[serde(rename = "fn")] pub function: FunctionConfig, @@ -680,6 +706,7 @@ impl Default for Config { macro_expansion: Default::default(), parse: ParseConfig::default(), export: ExportConfig::default(), + layout: LayoutConfig::default(), function: FunctionConfig::default(), structure: StructConfig::default(), enumeration: EnumConfig::default(), diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index e0d004537..22fbbb56c 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.rs @@ -102,6 +102,7 @@ impl EnumVariant { parse_fields(is_tagged, &fields.named)?, is_tagged, true, + None, false, false, Cfg::append(mod_cfg, Cfg::load(&variant.attrs)), @@ -117,6 +118,7 @@ impl EnumVariant { parse_fields(is_tagged, &fields.unnamed)?, is_tagged, true, + None, false, true, Cfg::append(mod_cfg, Cfg::load(&variant.attrs)), @@ -250,8 +252,12 @@ impl Enum { pub fn load(item: &syn::ItemEnum, mod_cfg: Option<&Cfg>) -> Result { let repr = Repr::load(&item.attrs)?; - if repr == Repr::RUST { - return Err("Enum not marked with a valid repr(prim) or repr(C).".to_owned()); + if repr.style == ReprStyle::Rust && repr.ty.is_none() { + return Err("Enum is not marked with a valid #[repr(prim)] or #[repr(C)].".to_owned()); + } + // TODO: Implement translation of aligned enums. + if repr.align.is_some() { + return Err("Enum is marked with #[repr(align(...))] or #[repr(packed)].".to_owned()); } let generic_params = GenericParams::new(&item.generics); diff --git a/src/bindgen/ir/repr.rs b/src/bindgen/ir/repr.rs index 1ed3f03b4..9ab10e384 100644 --- a/src/bindgen/ir/repr.rs +++ b/src/bindgen/ir/repr.rs @@ -29,28 +29,20 @@ pub enum ReprType { ISize, } +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum ReprAlign { + Packed, + Align(u64), +} + #[derive(Debug, Copy, Clone, PartialEq, Eq, Default)] pub struct Repr { pub style: ReprStyle, pub ty: Option, + pub align: Option, } impl Repr { - pub const C: Self = Repr { - style: ReprStyle::C, - ty: None, - }; - - pub const TRANSPARENT: Self = Repr { - style: ReprStyle::Transparent, - ty: None, - }; - - pub const RUST: Self = Repr { - style: ReprStyle::Rust, - ty: None, - }; - pub fn load(attrs: &[syn::Attribute]) -> Result { let ids = attrs .iter() @@ -67,33 +59,107 @@ impl Repr { .flat_map(|nested| nested) .filter_map(|meta| match meta { syn::NestedMeta::Meta(syn::Meta::Path(path)) => { - Some(path.segments.first().unwrap().ident.to_string()) + Some((path.segments.first().unwrap().ident.to_string(), None)) + } + syn::NestedMeta::Meta(syn::Meta::List(syn::MetaList { path, nested, .. })) => { + Some(( + path.segments.first().unwrap().ident.to_string(), + Some( + nested + .iter() + .filter_map(|meta| match meta { + // Only used for #[repr(align(...))]. + syn::NestedMeta::Lit(syn::Lit::Int(literal)) => { + Some(literal.base10_digits().to_string()) + } + // Only single levels of nesting supported at the moment. + _ => None, + }) + .collect::>(), + ), + )) } _ => None, }); let mut repr = Repr::default(); for id in ids { - let new_ty = match id.as_ref() { - "u8" => ReprType::U8, - "u16" => ReprType::U16, - "u32" => ReprType::U32, - "usize" => ReprType::USize, - "i8" => ReprType::I8, - "i16" => ReprType::I16, - "i32" => ReprType::I32, - "isize" => ReprType::ISize, - "C" => { + let new_ty = match (id.0.as_ref(), id.1) { + ("u8", None) => ReprType::U8, + ("u16", None) => ReprType::U16, + ("u32", None) => ReprType::U32, + ("usize", None) => ReprType::USize, + ("i8", None) => ReprType::I8, + ("i16", None) => ReprType::I16, + ("i32", None) => ReprType::I32, + ("isize", None) => ReprType::ISize, + ("C", None) => { repr.style = ReprStyle::C; continue; } - "transparent" => { + ("transparent", None) => { repr.style = ReprStyle::Transparent; continue; } - _ => { - return Err(format!("Unsupported #[repr({})].", id)); + ("packed", args) => { + // #[repr(packed(n))] not supported because of some open questions about how + // to calculate the native alignment of types. See eqrion/cbindgen#433. + if args.is_some() { + return Err(format!( + "Not-yet-implemented #[repr(packed(...))] encountered." + )); + } + let align = ReprAlign::Packed; + // Only permit a single alignment-setting repr. + if let Some(old_align) = repr.align { + return Err(format!( + "Conflicting #[repr(align(...))] type hints {:?} and {:?}.", + old_align, align + )); + } + repr.align = Some(align); + continue; + } + ("align", Some(args)) => { + // #[repr(align(...))] only allows a single argument. + if args.len() != 1 { + return Err(format!( + "Unsupported #[repr(align({}))], align must have exactly one argument.", + args.join(", ") + )); + } + // Must be a positive integer. + let align = match args.first().unwrap().parse::() { + Ok(align) => align, + Err(_) => { + return Err(format!("Non-numeric #[repr(align({}))].", args.join(", "))) + } + }; + // Must be a power of 2. + if !align.is_power_of_two() || align == 0 { + return Err(format!("Invalid alignment to #[repr(align({}))].", align)); + } + // Only permit a single alignment-setting repr. + if let Some(old_align) = repr.align { + return Err(format!( + "Conflicting #[repr(align(...))] type hints {:?} and {:?}.", + old_align, + ReprAlign::Align(align) + )); + } + repr.align = Some(ReprAlign::Align(align)); + continue; } + (path, args) => match args { + None => return Err(format!("Unsupported #[repr({})].", path)), + Some(args) => { + return Err(format!( + "Unsupported #[repr({}({}))].", + path, + args.join(", ") + )); + } + }, }; if let Some(old_ty) = repr.ty { return Err(format!( diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index a45f7f9f1..b717c0dcc 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -6,12 +6,12 @@ use std::io::Write; use syn; -use bindgen::config::{Config, Language}; +use bindgen::config::{Config, Language, LayoutConfig}; use bindgen::declarationtyperesolver::DeclarationTypeResolver; use bindgen::dependencies::Dependencies; use bindgen::ir::{ AnnotationSet, Cfg, ConditionWrite, Constant, Documentation, GenericParams, Item, - ItemContainer, Path, Repr, ToCondition, Type, Typedef, + ItemContainer, Path, Repr, ReprAlign, ReprStyle, ToCondition, Type, Typedef, }; use bindgen::library::Library; use bindgen::mangle; @@ -32,6 +32,7 @@ pub struct Struct { pub is_tagged: bool, /// Whether this is an enum variant body. pub is_enum_variant_body: bool, + pub alignment: Option, pub is_transparent: bool, pub tuple_struct: bool, pub cfg: Option, @@ -50,15 +51,25 @@ impl Struct { self.associated_constants.push(c); } - pub fn load(item: &syn::ItemStruct, mod_cfg: Option<&Cfg>) -> Result { - let is_transparent = match Repr::load(&item.attrs)? { - Repr::C => false, - Repr::TRANSPARENT => true, + pub fn load( + layout_config: &LayoutConfig, + item: &syn::ItemStruct, + mod_cfg: Option<&Cfg>, + ) -> Result { + let repr = Repr::load(&item.attrs)?; + let is_transparent = match repr.style { + ReprStyle::C => false, + ReprStyle::Transparent => true, _ => { return Err("Struct is not marked #[repr(C)] or #[repr(transparent)].".to_owned()); } }; + // Ensure we can safely represent the struct given the configuration. + if let Some(align) = repr.align { + layout_config.ensure_safe_to_represent(&align)?; + } + let (fields, tuple_struct) = match item.fields { syn::Fields::Unit => (Vec::new(), false), syn::Fields::Named(ref fields) => { @@ -90,6 +101,7 @@ impl Struct { fields, is_tagged, is_enum_variant_body, + repr.align, is_transparent, tuple_struct, Cfg::append(mod_cfg, Cfg::load(&item.attrs)), @@ -104,6 +116,7 @@ impl Struct { fields: Vec<(String, Type, Documentation)>, is_tagged: bool, is_enum_variant_body: bool, + alignment: Option, is_transparent: bool, tuple_struct: bool, cfg: Option, @@ -118,6 +131,7 @@ impl Struct { fields, is_tagged, is_enum_variant_body, + alignment, is_transparent, tuple_struct, cfg, @@ -166,6 +180,7 @@ impl Struct { .collect(), self.is_tagged, self.is_enum_variant_body, + self.alignment, self.is_transparent, self.tuple_struct, self.cfg.clone(), @@ -410,9 +425,24 @@ impl Source for Struct { out.write("struct"); + if let Some(align) = self.alignment { + match align { + ReprAlign::Packed => { + if let Some(ref anno) = config.layout.packed { + write!(out, " {}", anno); + } + } + ReprAlign::Align(n) => { + if let Some(ref anno) = config.layout.aligned_n { + write!(out, " {}({})", anno, n); + } + } + } + } + if self.annotations.must_use { if let Some(ref anno) = config.structure.must_use { - write!(out, " {}", anno) + write!(out, " {}", anno); } } diff --git a/src/bindgen/ir/union.rs b/src/bindgen/ir/union.rs index 9178eda09..a2effa59a 100644 --- a/src/bindgen/ir/union.rs +++ b/src/bindgen/ir/union.rs @@ -6,13 +6,13 @@ use std::io::Write; use syn; -use bindgen::config::{Config, Language}; +use bindgen::config::{Config, Language, LayoutConfig}; use bindgen::declarationtyperesolver::DeclarationTypeResolver; use bindgen::dependencies::Dependencies; use bindgen::ir::SynFieldHelpers; use bindgen::ir::{ AnnotationSet, Cfg, ConditionWrite, Documentation, GenericParams, Item, ItemContainer, Path, - Repr, ToCondition, Type, + Repr, ReprAlign, ReprStyle, ToCondition, Type, }; use bindgen::library::Library; use bindgen::mangle; @@ -28,17 +28,28 @@ pub struct Union { pub generic_params: GenericParams, pub fields: Vec<(String, Type, Documentation)>, pub tuple_union: bool, + pub alignment: Option, pub cfg: Option, pub annotations: AnnotationSet, pub documentation: Documentation, } impl Union { - pub fn load(item: &syn::ItemUnion, mod_cfg: Option<&Cfg>) -> Result { - if Repr::load(&item.attrs)? != Repr::C { + pub fn load( + layout_config: &LayoutConfig, + item: &syn::ItemUnion, + mod_cfg: Option<&Cfg>, + ) -> Result { + let repr = Repr::load(&item.attrs)?; + if repr.style != ReprStyle::C { return Err("Union is not marked #[repr(C)].".to_owned()); } + // Ensure we can safely represent the union given the configuration. + if let Some(align) = repr.align { + layout_config.ensure_safe_to_represent(&align)?; + } + let (fields, tuple_union) = { let out = item .fields @@ -52,6 +63,7 @@ impl Union { Path::new(item.ident.to_string()), GenericParams::new(&item.generics), fields, + repr.align, tuple_union, Cfg::append(mod_cfg, Cfg::load(&item.attrs)), AnnotationSet::load(&item.attrs)?, @@ -63,6 +75,7 @@ impl Union { path: Path, generic_params: GenericParams, fields: Vec<(String, Type, Documentation)>, + alignment: Option, tuple_union: bool, cfg: Option, annotations: AnnotationSet, @@ -74,6 +87,7 @@ impl Union { export_name, generic_params, fields, + alignment, tuple_union, cfg, annotations, @@ -228,6 +242,7 @@ impl Item for Union { .iter() .map(|x| (x.0.clone(), x.1.specialize(&mappings), x.2.clone())) .collect(), + self.alignment, self.tuple_union, self.cfg.clone(), self.annotations.clone(), @@ -263,6 +278,21 @@ impl Source for Union { out.write("union"); + if let Some(align) = self.alignment { + match align { + ReprAlign::Packed => { + if let Some(ref anno) = config.layout.packed { + write!(out, " {}", anno); + } + } + ReprAlign::Align(n) => { + if let Some(ref anno) = config.layout.aligned_n { + write!(out, " {}({})", anno, n); + } + } + } + } + if config.language == Language::Cxx || config.style.generate_tag() { write!(out, " {}", self.export_name); } diff --git a/src/bindgen/parser.rs b/src/bindgen/parser.rs index 50a7fde0a..67b3539cc 100644 --- a/src/bindgen/parser.rs +++ b/src/bindgen/parser.rs @@ -11,7 +11,7 @@ use syn; use bindgen::bitflags; use bindgen::cargo::{Cargo, PackageRef}; -use bindgen::config::{MacroExpansionConfig, ParseConfig}; +use bindgen::config::{Config, ParseConfig}; use bindgen::error::Error; use bindgen::ir::{ AnnotationSet, Cfg, Constant, Documentation, Enum, Function, GenericParams, ItemMap, @@ -31,20 +31,17 @@ const STD_CRATES: &[&str] = &[ type ParseResult = Result; /// Parses a single rust source file, not following `mod` or `extern crate`. -pub fn parse_src( - src_file: &FilePath, - macro_expansion_config: &MacroExpansionConfig, -) -> ParseResult { +pub fn parse_src(src_file: &FilePath, config: &Config) -> ParseResult { let mod_name = src_file.file_stem().unwrap().to_str().unwrap(); - let parse_config = ParseConfig { + let mut config = config.clone(); + config.parse = ParseConfig { parse_deps: true, ..ParseConfig::default() }; let mut context = Parser { binding_crate_name: mod_name.to_owned(), - macro_expansion_config, - parse_config: &parse_config, + config: &config, lib: None, parsed_crates: HashSet::new(), cache_src: HashMap::new(), @@ -67,15 +64,10 @@ pub fn parse_src( /// Inside a crate, `mod` and `extern crate` declarations are followed /// and parsed. To find an external crate, the parser uses the `cargo metadata` /// command to find the location of dependencies. -pub(crate) fn parse_lib( - lib: Cargo, - macro_expansion_config: &MacroExpansionConfig, - parse_config: &ParseConfig, -) -> ParseResult { +pub(crate) fn parse_lib(lib: Cargo, config: &Config) -> ParseResult { let mut context = Parser { binding_crate_name: lib.binding_crate_name().to_owned(), - macro_expansion_config, - parse_config, + config, lib: Some(lib), parsed_crates: HashSet::new(), cache_src: HashMap::new(), @@ -93,8 +85,7 @@ pub(crate) fn parse_lib( struct Parser<'a> { binding_crate_name: String, lib: Option, - macro_expansion_config: &'a MacroExpansionConfig, - parse_config: &'a ParseConfig, + config: &'a Config, parsed_crates: HashSet, cache_src: HashMap>, @@ -111,24 +102,24 @@ impl<'a> Parser<'a> { return false; } - if !self.parse_config.parse_deps { + if !self.config.parse.parse_deps { return false; } // Skip any whitelist or blacklist for expand - if self.parse_config.expand.crates.contains(&pkg_name) { + if self.config.parse.expand.crates.contains(&pkg_name) { return true; } // If we have a whitelist, check it - if let Some(ref include) = self.parse_config.include { + if let Some(ref include) = self.config.parse.include { if !include.contains(&pkg_name) { return false; } } // Check the blacklist - !STD_CRATES.contains(&pkg_name.as_ref()) && !self.parse_config.exclude.contains(&pkg_name) + !STD_CRATES.contains(&pkg_name.as_ref()) && !self.config.parse.exclude.contains(&pkg_name) } fn parse_crate(&mut self, pkg: &PackageRef) -> Result<(), Error> { @@ -136,7 +127,7 @@ impl<'a> Parser<'a> { self.parsed_crates.insert(pkg.name.clone()); // Check if we should use cargo expand for this crate - if self.parse_config.expand.crates.contains(&pkg.name) { + if self.config.parse.expand.crates.contains(&pkg.name) { self.parse_expand_crate(pkg)?; } else { // Parse the crate before the dependencies otherwise the same-named idents we @@ -193,9 +184,9 @@ impl<'a> Parser<'a> { .unwrap() .expand_crate( pkg, - self.parse_config.expand.all_features, - self.parse_config.expand.default_features, - &self.parse_config.expand.features, + self.config.parse.expand.all_features, + self.config.parse.expand.default_features, + &self.config.parse.expand.features, ) .map_err(|x| Error::CargoExpand(pkg.name.clone(), x))?; let i = syn::parse_file(&s).map_err(|x| Error::ParseSyntaxError { @@ -214,8 +205,7 @@ impl<'a> Parser<'a> { fn process_expanded_mod(&mut self, pkg: &PackageRef, items: &[syn::Item]) -> Result<(), Error> { self.out.load_syn_crate_mod( - &self.macro_expansion_config, - &self.parse_config, + &self.config, &self.binding_crate_name, &pkg.name, Cfg::join(&self.cfg_stack).as_ref(), @@ -287,8 +277,7 @@ impl<'a> Parser<'a> { items: &[syn::Item], ) -> Result<(), Error> { self.out.load_syn_crate_mod( - &self.macro_expansion_config, - &self.parse_config, + &self.config, &self.binding_crate_name, &pkg.name, Cfg::join(&self.cfg_stack).as_ref(), @@ -425,8 +414,7 @@ impl Parse { pub fn load_syn_crate_mod( &mut self, - macro_expansion_config: &MacroExpansionConfig, - parse_config: &ParseConfig, + config: &Config, binding_crate_name: &str, crate_name: &str, mod_cfg: Option<&Cfg>, @@ -441,7 +429,7 @@ impl Parse { match item { syn::Item::ForeignMod(ref item) => { self.load_syn_foreign_mod( - parse_config, + config, binding_crate_name, crate_name, mod_cfg, @@ -449,31 +437,19 @@ impl Parse { ); } syn::Item::Fn(ref item) => { - self.load_syn_fn(parse_config, binding_crate_name, crate_name, mod_cfg, item); + self.load_syn_fn(config, binding_crate_name, crate_name, mod_cfg, item); } syn::Item::Const(ref item) => { - self.load_syn_const( - parse_config, - binding_crate_name, - crate_name, - mod_cfg, - item, - ); + self.load_syn_const(config, binding_crate_name, crate_name, mod_cfg, item); } syn::Item::Static(ref item) => { - self.load_syn_static( - parse_config, - binding_crate_name, - crate_name, - mod_cfg, - item, - ); + self.load_syn_static(config, binding_crate_name, crate_name, mod_cfg, item); } syn::Item::Struct(ref item) => { - self.load_syn_struct(crate_name, mod_cfg, item); + self.load_syn_struct(config, crate_name, mod_cfg, item); } syn::Item::Union(ref item) => { - self.load_syn_union(crate_name, mod_cfg, item); + self.load_syn_union(config, crate_name, mod_cfg, item); } syn::Item::Enum(ref item) => { self.load_syn_enum(crate_name, mod_cfg, item); @@ -491,7 +467,7 @@ impl Parse { } } syn::Item::Macro(ref item) => { - self.load_builtin_macro(macro_expansion_config, crate_name, mod_cfg, item) + self.load_builtin_macro(config, crate_name, mod_cfg, item) } _ => {} } @@ -523,7 +499,7 @@ impl Parse { /// Enters a `extern "C" { }` declaration and loads function declarations. fn load_syn_foreign_mod( &mut self, - parse_config: &ParseConfig, + config: &Config, binding_crate_name: &str, crate_name: &str, mod_cfg: Option<&Cfg>, @@ -536,7 +512,10 @@ impl Parse { for foreign_item in &item.items { if let syn::ForeignItem::Fn(ref function) = *foreign_item { - if !parse_config.should_generate_top_level_item(crate_name, binding_crate_name) { + if !config + .parse + .should_generate_top_level_item(crate_name, binding_crate_name) + { info!( "Skip {}::{} - (fn's outside of the binding crate are not used).", crate_name, &function.sig.ident @@ -564,13 +543,16 @@ impl Parse { /// Loads a `fn` declaration fn load_syn_fn( &mut self, - parse_config: &ParseConfig, + config: &Config, binding_crate_name: &str, crate_name: &str, mod_cfg: Option<&Cfg>, item: &syn::ItemFn, ) { - if !parse_config.should_generate_top_level_item(crate_name, binding_crate_name) { + if !config + .parse + .should_generate_top_level_item(crate_name, binding_crate_name) + { info!( "Skip {}::{} - (fn's outside of the binding crate are not used).", crate_name, &item.sig.ident @@ -682,13 +664,16 @@ impl Parse { /// Loads a `const` declaration fn load_syn_const( &mut self, - parse_config: &ParseConfig, + config: &Config, binding_crate_name: &str, crate_name: &str, mod_cfg: Option<&Cfg>, item: &syn::ItemConst, ) { - if !parse_config.should_generate_top_level_item(crate_name, binding_crate_name) { + if !config + .parse + .should_generate_top_level_item(crate_name, binding_crate_name) + { info!( "Skip {}::{} - (const's outside of the binding crate are not used).", crate_name, &item.ident @@ -721,13 +706,16 @@ impl Parse { /// Loads a `static` declaration fn load_syn_static( &mut self, - parse_config: &ParseConfig, + config: &Config, binding_crate_name: &str, crate_name: &str, mod_cfg: Option<&Cfg>, item: &syn::ItemStatic, ) { - if !parse_config.should_generate_top_level_item(crate_name, binding_crate_name) { + if !config + .parse + .should_generate_top_level_item(crate_name, binding_crate_name) + { info!( "Skip {}::{} - (static's outside of the binding crate are not used).", crate_name, &item.ident @@ -761,8 +749,14 @@ impl Parse { } /// Loads a `struct` declaration - fn load_syn_struct(&mut self, crate_name: &str, mod_cfg: Option<&Cfg>, item: &syn::ItemStruct) { - match Struct::load(item, mod_cfg) { + fn load_syn_struct( + &mut self, + config: &Config, + crate_name: &str, + mod_cfg: Option<&Cfg>, + item: &syn::ItemStruct, + ) { + match Struct::load(&config.layout, item, mod_cfg) { Ok(st) => { info!("Take {}::{}.", crate_name, &item.ident); self.structs.try_insert(st); @@ -778,8 +772,14 @@ impl Parse { } /// Loads a `union` declaration - fn load_syn_union(&mut self, crate_name: &str, mod_cfg: Option<&Cfg>, item: &syn::ItemUnion) { - match Union::load(item, mod_cfg) { + fn load_syn_union( + &mut self, + config: &Config, + crate_name: &str, + mod_cfg: Option<&Cfg>, + item: &syn::ItemUnion, + ) { + match Union::load(&config.layout, item, mod_cfg) { Ok(st) => { info!("Take {}::{}.", crate_name, &item.ident); @@ -840,7 +840,7 @@ impl Parse { fn load_builtin_macro( &mut self, - macro_expansion_config: &MacroExpansionConfig, + config: &Config, crate_name: &str, mod_cfg: Option<&Cfg>, item: &syn::ItemMacro, @@ -850,7 +850,7 @@ impl Parse { None => return, }; - if name != "bitflags" || !macro_expansion_config.bitflags { + if name != "bitflags" || !config.macro_expansion.bitflags { return; } @@ -863,7 +863,7 @@ impl Parse { }; let (struct_, impl_) = bitflags.expand(); - self.load_syn_struct(crate_name, mod_cfg, &struct_); + self.load_syn_struct(config, crate_name, mod_cfg, &struct_); // We know that the expansion will only reference `struct_`, so it's // fine to just do it here instead of deferring it like we do with the // other calls to this function. diff --git a/tests/expectations/both/layout.c b/tests/expectations/both/layout.c new file mode 100644 index 000000000..2a16ca29a --- /dev/null +++ b/tests/expectations/both/layout.c @@ -0,0 +1,72 @@ +#define CBINDGEN_PACKED __attribute__ ((packed)) +#define CBINDGEN_ALIGNED(n) __attribute__ ((aligned(n))) + + +#include +#include +#include +#include + +typedef struct RustAlign4Struct RustAlign4Struct; + +typedef struct RustAlign4Union RustAlign4Union; + +typedef struct RustPackedStruct RustPackedStruct; + +typedef struct RustPackedUnion RustPackedUnion; + +typedef struct UnsupportedAlign4Enum UnsupportedAlign4Enum; + +typedef struct UnsupportedPacked4Struct UnsupportedPacked4Struct; + +typedef struct UnsupportedPacked4Union UnsupportedPacked4Union; + +typedef struct CBINDGEN_ALIGNED(1) Align1Struct { + uintptr_t arg1; + uint8_t *arg2; +} Align1Struct; + +typedef struct CBINDGEN_ALIGNED(2) Align2Struct { + uintptr_t arg1; + uint8_t *arg2; +} Align2Struct; + +typedef struct CBINDGEN_ALIGNED(4) Align4Struct { + uintptr_t arg1; + uint8_t *arg2; +} Align4Struct; + +typedef struct CBINDGEN_ALIGNED(8) Align8Struct { + uintptr_t arg1; + uint8_t *arg2; +} Align8Struct; + +typedef struct CBINDGEN_ALIGNED(32) Align32Struct { + uintptr_t arg1; + uint8_t *arg2; +} Align32Struct; + +typedef struct CBINDGEN_PACKED PackedStruct { + uintptr_t arg1; + uint8_t *arg2; +} PackedStruct; + +typedef union CBINDGEN_ALIGNED(1) Align1Union { + uintptr_t variant1; + uint8_t *variant2; +} Align1Union; + +typedef union CBINDGEN_ALIGNED(4) Align4Union { + uintptr_t variant1; + uint8_t *variant2; +} Align4Union; + +typedef union CBINDGEN_ALIGNED(16) Align16Union { + uintptr_t variant1; + uint8_t *variant2; +} Align16Union; + +typedef union CBINDGEN_PACKED PackedUnion { + uintptr_t variant1; + uint8_t *variant2; +} PackedUnion; diff --git a/tests/expectations/both/layout.compat.c b/tests/expectations/both/layout.compat.c new file mode 100644 index 000000000..2a16ca29a --- /dev/null +++ b/tests/expectations/both/layout.compat.c @@ -0,0 +1,72 @@ +#define CBINDGEN_PACKED __attribute__ ((packed)) +#define CBINDGEN_ALIGNED(n) __attribute__ ((aligned(n))) + + +#include +#include +#include +#include + +typedef struct RustAlign4Struct RustAlign4Struct; + +typedef struct RustAlign4Union RustAlign4Union; + +typedef struct RustPackedStruct RustPackedStruct; + +typedef struct RustPackedUnion RustPackedUnion; + +typedef struct UnsupportedAlign4Enum UnsupportedAlign4Enum; + +typedef struct UnsupportedPacked4Struct UnsupportedPacked4Struct; + +typedef struct UnsupportedPacked4Union UnsupportedPacked4Union; + +typedef struct CBINDGEN_ALIGNED(1) Align1Struct { + uintptr_t arg1; + uint8_t *arg2; +} Align1Struct; + +typedef struct CBINDGEN_ALIGNED(2) Align2Struct { + uintptr_t arg1; + uint8_t *arg2; +} Align2Struct; + +typedef struct CBINDGEN_ALIGNED(4) Align4Struct { + uintptr_t arg1; + uint8_t *arg2; +} Align4Struct; + +typedef struct CBINDGEN_ALIGNED(8) Align8Struct { + uintptr_t arg1; + uint8_t *arg2; +} Align8Struct; + +typedef struct CBINDGEN_ALIGNED(32) Align32Struct { + uintptr_t arg1; + uint8_t *arg2; +} Align32Struct; + +typedef struct CBINDGEN_PACKED PackedStruct { + uintptr_t arg1; + uint8_t *arg2; +} PackedStruct; + +typedef union CBINDGEN_ALIGNED(1) Align1Union { + uintptr_t variant1; + uint8_t *variant2; +} Align1Union; + +typedef union CBINDGEN_ALIGNED(4) Align4Union { + uintptr_t variant1; + uint8_t *variant2; +} Align4Union; + +typedef union CBINDGEN_ALIGNED(16) Align16Union { + uintptr_t variant1; + uint8_t *variant2; +} Align16Union; + +typedef union CBINDGEN_PACKED PackedUnion { + uintptr_t variant1; + uint8_t *variant2; +} PackedUnion; diff --git a/tests/expectations/both/layout_aligned_opaque.c b/tests/expectations/both/layout_aligned_opaque.c new file mode 100644 index 000000000..cc2891475 --- /dev/null +++ b/tests/expectations/both/layout_aligned_opaque.c @@ -0,0 +1,34 @@ +#define CBINDGEN_PACKED __attribute__ ((packed)) +#define CBINDGEN_ALIGNED(n) __attribute__ ((aligned(n))) + + +#include +#include +#include +#include + +typedef struct OpaqueAlign16Union OpaqueAlign16Union; + +typedef struct OpaqueAlign1Struct OpaqueAlign1Struct; + +typedef struct OpaqueAlign1Union OpaqueAlign1Union; + +typedef struct OpaqueAlign2Struct OpaqueAlign2Struct; + +typedef struct OpaqueAlign32Struct OpaqueAlign32Struct; + +typedef struct OpaqueAlign4Struct OpaqueAlign4Struct; + +typedef struct OpaqueAlign4Union OpaqueAlign4Union; + +typedef struct OpaqueAlign8Struct OpaqueAlign8Struct; + +typedef struct CBINDGEN_PACKED PackedStruct { + uintptr_t arg1; + uint8_t *arg2; +} PackedStruct; + +typedef union CBINDGEN_PACKED PackedUnion { + uintptr_t variant1; + uint8_t *variant2; +} PackedUnion; diff --git a/tests/expectations/both/layout_aligned_opaque.compat.c b/tests/expectations/both/layout_aligned_opaque.compat.c new file mode 100644 index 000000000..cc2891475 --- /dev/null +++ b/tests/expectations/both/layout_aligned_opaque.compat.c @@ -0,0 +1,34 @@ +#define CBINDGEN_PACKED __attribute__ ((packed)) +#define CBINDGEN_ALIGNED(n) __attribute__ ((aligned(n))) + + +#include +#include +#include +#include + +typedef struct OpaqueAlign16Union OpaqueAlign16Union; + +typedef struct OpaqueAlign1Struct OpaqueAlign1Struct; + +typedef struct OpaqueAlign1Union OpaqueAlign1Union; + +typedef struct OpaqueAlign2Struct OpaqueAlign2Struct; + +typedef struct OpaqueAlign32Struct OpaqueAlign32Struct; + +typedef struct OpaqueAlign4Struct OpaqueAlign4Struct; + +typedef struct OpaqueAlign4Union OpaqueAlign4Union; + +typedef struct OpaqueAlign8Struct OpaqueAlign8Struct; + +typedef struct CBINDGEN_PACKED PackedStruct { + uintptr_t arg1; + uint8_t *arg2; +} PackedStruct; + +typedef union CBINDGEN_PACKED PackedUnion { + uintptr_t variant1; + uint8_t *variant2; +} PackedUnion; diff --git a/tests/expectations/both/layout_packed_opaque.c b/tests/expectations/both/layout_packed_opaque.c new file mode 100644 index 000000000..ff9053fd0 --- /dev/null +++ b/tests/expectations/both/layout_packed_opaque.c @@ -0,0 +1,52 @@ +#define CBINDGEN_PACKED __attribute__ ((packed)) +#define CBINDGEN_ALIGNED(n) __attribute__ ((aligned(n))) + + +#include +#include +#include +#include + +typedef struct OpaquePackedStruct OpaquePackedStruct; + +typedef struct OpaquePackedUnion OpaquePackedUnion; + +typedef union CBINDGEN_ALIGNED(1) Align1Union { + uintptr_t variant1; + uint8_t *variant2; +} Align1Union; + +typedef union CBINDGEN_ALIGNED(4) Align4Union { + uintptr_t variant1; + uint8_t *variant2; +} Align4Union; + +typedef union CBINDGEN_ALIGNED(16) Align16Union { + uintptr_t variant1; + uint8_t *variant2; +} Align16Union; + +typedef struct CBINDGEN_ALIGNED(1) Align1Struct { + uintptr_t arg1; + uint8_t *arg2; +} Align1Struct; + +typedef struct CBINDGEN_ALIGNED(2) Align2Struct { + uintptr_t arg1; + uint8_t *arg2; +} Align2Struct; + +typedef struct CBINDGEN_ALIGNED(4) Align4Struct { + uintptr_t arg1; + uint8_t *arg2; +} Align4Struct; + +typedef struct CBINDGEN_ALIGNED(8) Align8Struct { + uintptr_t arg1; + uint8_t *arg2; +} Align8Struct; + +typedef struct CBINDGEN_ALIGNED(32) Align32Struct { + uintptr_t arg1; + uint8_t *arg2; +} Align32Struct; diff --git a/tests/expectations/both/layout_packed_opaque.compat.c b/tests/expectations/both/layout_packed_opaque.compat.c new file mode 100644 index 000000000..ff9053fd0 --- /dev/null +++ b/tests/expectations/both/layout_packed_opaque.compat.c @@ -0,0 +1,52 @@ +#define CBINDGEN_PACKED __attribute__ ((packed)) +#define CBINDGEN_ALIGNED(n) __attribute__ ((aligned(n))) + + +#include +#include +#include +#include + +typedef struct OpaquePackedStruct OpaquePackedStruct; + +typedef struct OpaquePackedUnion OpaquePackedUnion; + +typedef union CBINDGEN_ALIGNED(1) Align1Union { + uintptr_t variant1; + uint8_t *variant2; +} Align1Union; + +typedef union CBINDGEN_ALIGNED(4) Align4Union { + uintptr_t variant1; + uint8_t *variant2; +} Align4Union; + +typedef union CBINDGEN_ALIGNED(16) Align16Union { + uintptr_t variant1; + uint8_t *variant2; +} Align16Union; + +typedef struct CBINDGEN_ALIGNED(1) Align1Struct { + uintptr_t arg1; + uint8_t *arg2; +} Align1Struct; + +typedef struct CBINDGEN_ALIGNED(2) Align2Struct { + uintptr_t arg1; + uint8_t *arg2; +} Align2Struct; + +typedef struct CBINDGEN_ALIGNED(4) Align4Struct { + uintptr_t arg1; + uint8_t *arg2; +} Align4Struct; + +typedef struct CBINDGEN_ALIGNED(8) Align8Struct { + uintptr_t arg1; + uint8_t *arg2; +} Align8Struct; + +typedef struct CBINDGEN_ALIGNED(32) Align32Struct { + uintptr_t arg1; + uint8_t *arg2; +} Align32Struct; diff --git a/tests/expectations/layout.c b/tests/expectations/layout.c new file mode 100644 index 000000000..bd06ba5c8 --- /dev/null +++ b/tests/expectations/layout.c @@ -0,0 +1,72 @@ +#define CBINDGEN_PACKED __attribute__ ((packed)) +#define CBINDGEN_ALIGNED(n) __attribute__ ((aligned(n))) + + +#include +#include +#include +#include + +typedef struct RustAlign4Struct RustAlign4Struct; + +typedef struct RustAlign4Union RustAlign4Union; + +typedef struct RustPackedStruct RustPackedStruct; + +typedef struct RustPackedUnion RustPackedUnion; + +typedef struct UnsupportedAlign4Enum UnsupportedAlign4Enum; + +typedef struct UnsupportedPacked4Struct UnsupportedPacked4Struct; + +typedef struct UnsupportedPacked4Union UnsupportedPacked4Union; + +typedef struct CBINDGEN_ALIGNED(1) { + uintptr_t arg1; + uint8_t *arg2; +} Align1Struct; + +typedef struct CBINDGEN_ALIGNED(2) { + uintptr_t arg1; + uint8_t *arg2; +} Align2Struct; + +typedef struct CBINDGEN_ALIGNED(4) { + uintptr_t arg1; + uint8_t *arg2; +} Align4Struct; + +typedef struct CBINDGEN_ALIGNED(8) { + uintptr_t arg1; + uint8_t *arg2; +} Align8Struct; + +typedef struct CBINDGEN_ALIGNED(32) { + uintptr_t arg1; + uint8_t *arg2; +} Align32Struct; + +typedef struct CBINDGEN_PACKED { + uintptr_t arg1; + uint8_t *arg2; +} PackedStruct; + +typedef union CBINDGEN_ALIGNED(1) { + uintptr_t variant1; + uint8_t *variant2; +} Align1Union; + +typedef union CBINDGEN_ALIGNED(4) { + uintptr_t variant1; + uint8_t *variant2; +} Align4Union; + +typedef union CBINDGEN_ALIGNED(16) { + uintptr_t variant1; + uint8_t *variant2; +} Align16Union; + +typedef union CBINDGEN_PACKED { + uintptr_t variant1; + uint8_t *variant2; +} PackedUnion; diff --git a/tests/expectations/layout.compat.c b/tests/expectations/layout.compat.c new file mode 100644 index 000000000..bd06ba5c8 --- /dev/null +++ b/tests/expectations/layout.compat.c @@ -0,0 +1,72 @@ +#define CBINDGEN_PACKED __attribute__ ((packed)) +#define CBINDGEN_ALIGNED(n) __attribute__ ((aligned(n))) + + +#include +#include +#include +#include + +typedef struct RustAlign4Struct RustAlign4Struct; + +typedef struct RustAlign4Union RustAlign4Union; + +typedef struct RustPackedStruct RustPackedStruct; + +typedef struct RustPackedUnion RustPackedUnion; + +typedef struct UnsupportedAlign4Enum UnsupportedAlign4Enum; + +typedef struct UnsupportedPacked4Struct UnsupportedPacked4Struct; + +typedef struct UnsupportedPacked4Union UnsupportedPacked4Union; + +typedef struct CBINDGEN_ALIGNED(1) { + uintptr_t arg1; + uint8_t *arg2; +} Align1Struct; + +typedef struct CBINDGEN_ALIGNED(2) { + uintptr_t arg1; + uint8_t *arg2; +} Align2Struct; + +typedef struct CBINDGEN_ALIGNED(4) { + uintptr_t arg1; + uint8_t *arg2; +} Align4Struct; + +typedef struct CBINDGEN_ALIGNED(8) { + uintptr_t arg1; + uint8_t *arg2; +} Align8Struct; + +typedef struct CBINDGEN_ALIGNED(32) { + uintptr_t arg1; + uint8_t *arg2; +} Align32Struct; + +typedef struct CBINDGEN_PACKED { + uintptr_t arg1; + uint8_t *arg2; +} PackedStruct; + +typedef union CBINDGEN_ALIGNED(1) { + uintptr_t variant1; + uint8_t *variant2; +} Align1Union; + +typedef union CBINDGEN_ALIGNED(4) { + uintptr_t variant1; + uint8_t *variant2; +} Align4Union; + +typedef union CBINDGEN_ALIGNED(16) { + uintptr_t variant1; + uint8_t *variant2; +} Align16Union; + +typedef union CBINDGEN_PACKED { + uintptr_t variant1; + uint8_t *variant2; +} PackedUnion; diff --git a/tests/expectations/layout.cpp b/tests/expectations/layout.cpp new file mode 100644 index 000000000..b3ba1bedb --- /dev/null +++ b/tests/expectations/layout.cpp @@ -0,0 +1,72 @@ +#define CBINDGEN_PACKED __attribute__ ((packed)) +#define CBINDGEN_ALIGNED(n) __attribute__ ((aligned(n))) + + +#include +#include +#include +#include + +struct RustAlign4Struct; + +struct RustAlign4Union; + +struct RustPackedStruct; + +struct RustPackedUnion; + +struct UnsupportedAlign4Enum; + +struct UnsupportedPacked4Struct; + +struct UnsupportedPacked4Union; + +struct CBINDGEN_ALIGNED(1) Align1Struct { + uintptr_t arg1; + uint8_t *arg2; +}; + +struct CBINDGEN_ALIGNED(2) Align2Struct { + uintptr_t arg1; + uint8_t *arg2; +}; + +struct CBINDGEN_ALIGNED(4) Align4Struct { + uintptr_t arg1; + uint8_t *arg2; +}; + +struct CBINDGEN_ALIGNED(8) Align8Struct { + uintptr_t arg1; + uint8_t *arg2; +}; + +struct CBINDGEN_ALIGNED(32) Align32Struct { + uintptr_t arg1; + uint8_t *arg2; +}; + +struct CBINDGEN_PACKED PackedStruct { + uintptr_t arg1; + uint8_t *arg2; +}; + +union CBINDGEN_ALIGNED(1) Align1Union { + uintptr_t variant1; + uint8_t *variant2; +}; + +union CBINDGEN_ALIGNED(4) Align4Union { + uintptr_t variant1; + uint8_t *variant2; +}; + +union CBINDGEN_ALIGNED(16) Align16Union { + uintptr_t variant1; + uint8_t *variant2; +}; + +union CBINDGEN_PACKED PackedUnion { + uintptr_t variant1; + uint8_t *variant2; +}; diff --git a/tests/expectations/layout_aligned_opaque.c b/tests/expectations/layout_aligned_opaque.c new file mode 100644 index 000000000..276173b54 --- /dev/null +++ b/tests/expectations/layout_aligned_opaque.c @@ -0,0 +1,34 @@ +#define CBINDGEN_PACKED __attribute__ ((packed)) +#define CBINDGEN_ALIGNED(n) __attribute__ ((aligned(n))) + + +#include +#include +#include +#include + +typedef struct OpaqueAlign16Union OpaqueAlign16Union; + +typedef struct OpaqueAlign1Struct OpaqueAlign1Struct; + +typedef struct OpaqueAlign1Union OpaqueAlign1Union; + +typedef struct OpaqueAlign2Struct OpaqueAlign2Struct; + +typedef struct OpaqueAlign32Struct OpaqueAlign32Struct; + +typedef struct OpaqueAlign4Struct OpaqueAlign4Struct; + +typedef struct OpaqueAlign4Union OpaqueAlign4Union; + +typedef struct OpaqueAlign8Struct OpaqueAlign8Struct; + +typedef struct CBINDGEN_PACKED { + uintptr_t arg1; + uint8_t *arg2; +} PackedStruct; + +typedef union CBINDGEN_PACKED { + uintptr_t variant1; + uint8_t *variant2; +} PackedUnion; diff --git a/tests/expectations/layout_aligned_opaque.compat.c b/tests/expectations/layout_aligned_opaque.compat.c new file mode 100644 index 000000000..276173b54 --- /dev/null +++ b/tests/expectations/layout_aligned_opaque.compat.c @@ -0,0 +1,34 @@ +#define CBINDGEN_PACKED __attribute__ ((packed)) +#define CBINDGEN_ALIGNED(n) __attribute__ ((aligned(n))) + + +#include +#include +#include +#include + +typedef struct OpaqueAlign16Union OpaqueAlign16Union; + +typedef struct OpaqueAlign1Struct OpaqueAlign1Struct; + +typedef struct OpaqueAlign1Union OpaqueAlign1Union; + +typedef struct OpaqueAlign2Struct OpaqueAlign2Struct; + +typedef struct OpaqueAlign32Struct OpaqueAlign32Struct; + +typedef struct OpaqueAlign4Struct OpaqueAlign4Struct; + +typedef struct OpaqueAlign4Union OpaqueAlign4Union; + +typedef struct OpaqueAlign8Struct OpaqueAlign8Struct; + +typedef struct CBINDGEN_PACKED { + uintptr_t arg1; + uint8_t *arg2; +} PackedStruct; + +typedef union CBINDGEN_PACKED { + uintptr_t variant1; + uint8_t *variant2; +} PackedUnion; diff --git a/tests/expectations/layout_aligned_opaque.cpp b/tests/expectations/layout_aligned_opaque.cpp new file mode 100644 index 000000000..3b25ae54b --- /dev/null +++ b/tests/expectations/layout_aligned_opaque.cpp @@ -0,0 +1,34 @@ +#define CBINDGEN_PACKED __attribute__ ((packed)) +#define CBINDGEN_ALIGNED(n) __attribute__ ((aligned(n))) + + +#include +#include +#include +#include + +struct OpaqueAlign16Union; + +struct OpaqueAlign1Struct; + +struct OpaqueAlign1Union; + +struct OpaqueAlign2Struct; + +struct OpaqueAlign32Struct; + +struct OpaqueAlign4Struct; + +struct OpaqueAlign4Union; + +struct OpaqueAlign8Struct; + +struct CBINDGEN_PACKED PackedStruct { + uintptr_t arg1; + uint8_t *arg2; +}; + +union CBINDGEN_PACKED PackedUnion { + uintptr_t variant1; + uint8_t *variant2; +}; diff --git a/tests/expectations/layout_packed_opaque.c b/tests/expectations/layout_packed_opaque.c new file mode 100644 index 000000000..b4018dab5 --- /dev/null +++ b/tests/expectations/layout_packed_opaque.c @@ -0,0 +1,52 @@ +#define CBINDGEN_PACKED __attribute__ ((packed)) +#define CBINDGEN_ALIGNED(n) __attribute__ ((aligned(n))) + + +#include +#include +#include +#include + +typedef struct OpaquePackedStruct OpaquePackedStruct; + +typedef struct OpaquePackedUnion OpaquePackedUnion; + +typedef union CBINDGEN_ALIGNED(1) { + uintptr_t variant1; + uint8_t *variant2; +} Align1Union; + +typedef union CBINDGEN_ALIGNED(4) { + uintptr_t variant1; + uint8_t *variant2; +} Align4Union; + +typedef union CBINDGEN_ALIGNED(16) { + uintptr_t variant1; + uint8_t *variant2; +} Align16Union; + +typedef struct CBINDGEN_ALIGNED(1) { + uintptr_t arg1; + uint8_t *arg2; +} Align1Struct; + +typedef struct CBINDGEN_ALIGNED(2) { + uintptr_t arg1; + uint8_t *arg2; +} Align2Struct; + +typedef struct CBINDGEN_ALIGNED(4) { + uintptr_t arg1; + uint8_t *arg2; +} Align4Struct; + +typedef struct CBINDGEN_ALIGNED(8) { + uintptr_t arg1; + uint8_t *arg2; +} Align8Struct; + +typedef struct CBINDGEN_ALIGNED(32) { + uintptr_t arg1; + uint8_t *arg2; +} Align32Struct; diff --git a/tests/expectations/layout_packed_opaque.compat.c b/tests/expectations/layout_packed_opaque.compat.c new file mode 100644 index 000000000..b4018dab5 --- /dev/null +++ b/tests/expectations/layout_packed_opaque.compat.c @@ -0,0 +1,52 @@ +#define CBINDGEN_PACKED __attribute__ ((packed)) +#define CBINDGEN_ALIGNED(n) __attribute__ ((aligned(n))) + + +#include +#include +#include +#include + +typedef struct OpaquePackedStruct OpaquePackedStruct; + +typedef struct OpaquePackedUnion OpaquePackedUnion; + +typedef union CBINDGEN_ALIGNED(1) { + uintptr_t variant1; + uint8_t *variant2; +} Align1Union; + +typedef union CBINDGEN_ALIGNED(4) { + uintptr_t variant1; + uint8_t *variant2; +} Align4Union; + +typedef union CBINDGEN_ALIGNED(16) { + uintptr_t variant1; + uint8_t *variant2; +} Align16Union; + +typedef struct CBINDGEN_ALIGNED(1) { + uintptr_t arg1; + uint8_t *arg2; +} Align1Struct; + +typedef struct CBINDGEN_ALIGNED(2) { + uintptr_t arg1; + uint8_t *arg2; +} Align2Struct; + +typedef struct CBINDGEN_ALIGNED(4) { + uintptr_t arg1; + uint8_t *arg2; +} Align4Struct; + +typedef struct CBINDGEN_ALIGNED(8) { + uintptr_t arg1; + uint8_t *arg2; +} Align8Struct; + +typedef struct CBINDGEN_ALIGNED(32) { + uintptr_t arg1; + uint8_t *arg2; +} Align32Struct; diff --git a/tests/expectations/layout_packed_opaque.cpp b/tests/expectations/layout_packed_opaque.cpp new file mode 100644 index 000000000..1e3c4a956 --- /dev/null +++ b/tests/expectations/layout_packed_opaque.cpp @@ -0,0 +1,52 @@ +#define CBINDGEN_PACKED __attribute__ ((packed)) +#define CBINDGEN_ALIGNED(n) __attribute__ ((aligned(n))) + + +#include +#include +#include +#include + +struct OpaquePackedStruct; + +struct OpaquePackedUnion; + +union CBINDGEN_ALIGNED(1) Align1Union { + uintptr_t variant1; + uint8_t *variant2; +}; + +union CBINDGEN_ALIGNED(4) Align4Union { + uintptr_t variant1; + uint8_t *variant2; +}; + +union CBINDGEN_ALIGNED(16) Align16Union { + uintptr_t variant1; + uint8_t *variant2; +}; + +struct CBINDGEN_ALIGNED(1) Align1Struct { + uintptr_t arg1; + uint8_t *arg2; +}; + +struct CBINDGEN_ALIGNED(2) Align2Struct { + uintptr_t arg1; + uint8_t *arg2; +}; + +struct CBINDGEN_ALIGNED(4) Align4Struct { + uintptr_t arg1; + uint8_t *arg2; +}; + +struct CBINDGEN_ALIGNED(8) Align8Struct { + uintptr_t arg1; + uint8_t *arg2; +}; + +struct CBINDGEN_ALIGNED(32) Align32Struct { + uintptr_t arg1; + uint8_t *arg2; +}; diff --git a/tests/expectations/tag/layout.c b/tests/expectations/tag/layout.c new file mode 100644 index 000000000..347af2754 --- /dev/null +++ b/tests/expectations/tag/layout.c @@ -0,0 +1,72 @@ +#define CBINDGEN_PACKED __attribute__ ((packed)) +#define CBINDGEN_ALIGNED(n) __attribute__ ((aligned(n))) + + +#include +#include +#include +#include + +struct RustAlign4Struct; + +struct RustAlign4Union; + +struct RustPackedStruct; + +struct RustPackedUnion; + +struct UnsupportedAlign4Enum; + +struct UnsupportedPacked4Struct; + +struct UnsupportedPacked4Union; + +struct CBINDGEN_ALIGNED(1) Align1Struct { + uintptr_t arg1; + uint8_t *arg2; +}; + +struct CBINDGEN_ALIGNED(2) Align2Struct { + uintptr_t arg1; + uint8_t *arg2; +}; + +struct CBINDGEN_ALIGNED(4) Align4Struct { + uintptr_t arg1; + uint8_t *arg2; +}; + +struct CBINDGEN_ALIGNED(8) Align8Struct { + uintptr_t arg1; + uint8_t *arg2; +}; + +struct CBINDGEN_ALIGNED(32) Align32Struct { + uintptr_t arg1; + uint8_t *arg2; +}; + +struct CBINDGEN_PACKED PackedStruct { + uintptr_t arg1; + uint8_t *arg2; +}; + +union CBINDGEN_ALIGNED(1) Align1Union { + uintptr_t variant1; + uint8_t *variant2; +}; + +union CBINDGEN_ALIGNED(4) Align4Union { + uintptr_t variant1; + uint8_t *variant2; +}; + +union CBINDGEN_ALIGNED(16) Align16Union { + uintptr_t variant1; + uint8_t *variant2; +}; + +union CBINDGEN_PACKED PackedUnion { + uintptr_t variant1; + uint8_t *variant2; +}; diff --git a/tests/expectations/tag/layout.compat.c b/tests/expectations/tag/layout.compat.c new file mode 100644 index 000000000..347af2754 --- /dev/null +++ b/tests/expectations/tag/layout.compat.c @@ -0,0 +1,72 @@ +#define CBINDGEN_PACKED __attribute__ ((packed)) +#define CBINDGEN_ALIGNED(n) __attribute__ ((aligned(n))) + + +#include +#include +#include +#include + +struct RustAlign4Struct; + +struct RustAlign4Union; + +struct RustPackedStruct; + +struct RustPackedUnion; + +struct UnsupportedAlign4Enum; + +struct UnsupportedPacked4Struct; + +struct UnsupportedPacked4Union; + +struct CBINDGEN_ALIGNED(1) Align1Struct { + uintptr_t arg1; + uint8_t *arg2; +}; + +struct CBINDGEN_ALIGNED(2) Align2Struct { + uintptr_t arg1; + uint8_t *arg2; +}; + +struct CBINDGEN_ALIGNED(4) Align4Struct { + uintptr_t arg1; + uint8_t *arg2; +}; + +struct CBINDGEN_ALIGNED(8) Align8Struct { + uintptr_t arg1; + uint8_t *arg2; +}; + +struct CBINDGEN_ALIGNED(32) Align32Struct { + uintptr_t arg1; + uint8_t *arg2; +}; + +struct CBINDGEN_PACKED PackedStruct { + uintptr_t arg1; + uint8_t *arg2; +}; + +union CBINDGEN_ALIGNED(1) Align1Union { + uintptr_t variant1; + uint8_t *variant2; +}; + +union CBINDGEN_ALIGNED(4) Align4Union { + uintptr_t variant1; + uint8_t *variant2; +}; + +union CBINDGEN_ALIGNED(16) Align16Union { + uintptr_t variant1; + uint8_t *variant2; +}; + +union CBINDGEN_PACKED PackedUnion { + uintptr_t variant1; + uint8_t *variant2; +}; diff --git a/tests/expectations/tag/layout_aligned_opaque.c b/tests/expectations/tag/layout_aligned_opaque.c new file mode 100644 index 000000000..0c5def9be --- /dev/null +++ b/tests/expectations/tag/layout_aligned_opaque.c @@ -0,0 +1,34 @@ +#define CBINDGEN_PACKED __attribute__ ((packed)) +#define CBINDGEN_ALIGNED(n) __attribute__ ((aligned(n))) + + +#include +#include +#include +#include + +struct OpaqueAlign16Union; + +struct OpaqueAlign1Struct; + +struct OpaqueAlign1Union; + +struct OpaqueAlign2Struct; + +struct OpaqueAlign32Struct; + +struct OpaqueAlign4Struct; + +struct OpaqueAlign4Union; + +struct OpaqueAlign8Struct; + +struct CBINDGEN_PACKED PackedStruct { + uintptr_t arg1; + uint8_t *arg2; +}; + +union CBINDGEN_PACKED PackedUnion { + uintptr_t variant1; + uint8_t *variant2; +}; diff --git a/tests/expectations/tag/layout_aligned_opaque.compat.c b/tests/expectations/tag/layout_aligned_opaque.compat.c new file mode 100644 index 000000000..0c5def9be --- /dev/null +++ b/tests/expectations/tag/layout_aligned_opaque.compat.c @@ -0,0 +1,34 @@ +#define CBINDGEN_PACKED __attribute__ ((packed)) +#define CBINDGEN_ALIGNED(n) __attribute__ ((aligned(n))) + + +#include +#include +#include +#include + +struct OpaqueAlign16Union; + +struct OpaqueAlign1Struct; + +struct OpaqueAlign1Union; + +struct OpaqueAlign2Struct; + +struct OpaqueAlign32Struct; + +struct OpaqueAlign4Struct; + +struct OpaqueAlign4Union; + +struct OpaqueAlign8Struct; + +struct CBINDGEN_PACKED PackedStruct { + uintptr_t arg1; + uint8_t *arg2; +}; + +union CBINDGEN_PACKED PackedUnion { + uintptr_t variant1; + uint8_t *variant2; +}; diff --git a/tests/expectations/tag/layout_packed_opaque.c b/tests/expectations/tag/layout_packed_opaque.c new file mode 100644 index 000000000..8191f570c --- /dev/null +++ b/tests/expectations/tag/layout_packed_opaque.c @@ -0,0 +1,52 @@ +#define CBINDGEN_PACKED __attribute__ ((packed)) +#define CBINDGEN_ALIGNED(n) __attribute__ ((aligned(n))) + + +#include +#include +#include +#include + +struct OpaquePackedStruct; + +struct OpaquePackedUnion; + +union CBINDGEN_ALIGNED(1) Align1Union { + uintptr_t variant1; + uint8_t *variant2; +}; + +union CBINDGEN_ALIGNED(4) Align4Union { + uintptr_t variant1; + uint8_t *variant2; +}; + +union CBINDGEN_ALIGNED(16) Align16Union { + uintptr_t variant1; + uint8_t *variant2; +}; + +struct CBINDGEN_ALIGNED(1) Align1Struct { + uintptr_t arg1; + uint8_t *arg2; +}; + +struct CBINDGEN_ALIGNED(2) Align2Struct { + uintptr_t arg1; + uint8_t *arg2; +}; + +struct CBINDGEN_ALIGNED(4) Align4Struct { + uintptr_t arg1; + uint8_t *arg2; +}; + +struct CBINDGEN_ALIGNED(8) Align8Struct { + uintptr_t arg1; + uint8_t *arg2; +}; + +struct CBINDGEN_ALIGNED(32) Align32Struct { + uintptr_t arg1; + uint8_t *arg2; +}; diff --git a/tests/expectations/tag/layout_packed_opaque.compat.c b/tests/expectations/tag/layout_packed_opaque.compat.c new file mode 100644 index 000000000..8191f570c --- /dev/null +++ b/tests/expectations/tag/layout_packed_opaque.compat.c @@ -0,0 +1,52 @@ +#define CBINDGEN_PACKED __attribute__ ((packed)) +#define CBINDGEN_ALIGNED(n) __attribute__ ((aligned(n))) + + +#include +#include +#include +#include + +struct OpaquePackedStruct; + +struct OpaquePackedUnion; + +union CBINDGEN_ALIGNED(1) Align1Union { + uintptr_t variant1; + uint8_t *variant2; +}; + +union CBINDGEN_ALIGNED(4) Align4Union { + uintptr_t variant1; + uint8_t *variant2; +}; + +union CBINDGEN_ALIGNED(16) Align16Union { + uintptr_t variant1; + uint8_t *variant2; +}; + +struct CBINDGEN_ALIGNED(1) Align1Struct { + uintptr_t arg1; + uint8_t *arg2; +}; + +struct CBINDGEN_ALIGNED(2) Align2Struct { + uintptr_t arg1; + uint8_t *arg2; +}; + +struct CBINDGEN_ALIGNED(4) Align4Struct { + uintptr_t arg1; + uint8_t *arg2; +}; + +struct CBINDGEN_ALIGNED(8) Align8Struct { + uintptr_t arg1; + uint8_t *arg2; +}; + +struct CBINDGEN_ALIGNED(32) Align32Struct { + uintptr_t arg1; + uint8_t *arg2; +}; diff --git a/tests/rust/layout.rs b/tests/rust/layout.rs new file mode 100644 index 000000000..b15c67585 --- /dev/null +++ b/tests/rust/layout.rs @@ -0,0 +1,108 @@ +#[repr(align(1), C)] +pub struct Align1Struct { + pub arg1: usize, + pub arg2: *mut u8, +} + +#[repr(align(2), C)] +pub struct Align2Struct { + pub arg1: usize, + pub arg2: *mut u8, +} + +#[repr(align(4), C)] +pub struct Align4Struct { + pub arg1: usize, + pub arg2: *mut u8, +} + +#[repr(align(8), C)] +pub struct Align8Struct { + pub arg1: usize, + pub arg2: *mut u8, +} + +#[repr(align(32), C)] +pub struct Align32Struct { + pub arg1: usize, + pub arg2: *mut u8, +} + +#[repr(packed, C)] +pub struct PackedStruct { + pub arg1: usize, + pub arg2: *mut u8, +} + +#[repr(align(1), C)] +pub union Align1Union { + pub variant1: usize, + pub variant2: *mut u8, +} + +#[repr(align(4), C)] +pub union Align4Union { + pub variant1: usize, + pub variant2: *mut u8, +} + +#[repr(align(16), C)] +pub union Align16Union { + pub variant1: usize, + pub variant2: *mut u8, +} + +#[repr(packed, C)] +pub union PackedUnion { + pub variant1: usize, + pub variant2: *mut u8, +} + +// #[repr(packed(n), C)] structs are currently unsupported. +#[repr(packed(4), C)] +pub struct UnsupportedPacked4Struct { + pub arg1: usize, + pub arg2: *mut u8, +} + +// #[repr(packed(n), C)] unions are currently unsupported. +#[repr(packed(4), C)] +pub union UnsupportedPacked4Union { + pub variant1: usize, + pub variant2: *mut u8, +} + +// #[repr(align(n), C)] enums are currently unsupported. +#[repr(align(4), C)] +pub enum UnsupportedAlign4Enum { + Variant1, + Variant2, +} + +// Non-repr(C) structs aren't translated. +#[repr(align(4))] +pub struct RustAlign4Struct { + pub arg1: usize, + pub arg2: *mut u8, +} + +// Non-repr(C) structs aren't translated. +#[repr(packed)] +pub struct RustPackedStruct { + pub arg1: usize, + pub arg2: *mut u8, +} + +// Non-repr(C) unions aren't translated. +#[repr(align(4))] +pub struct RustAlign4Union { + pub arg1: usize, + pub arg2: *mut u8, +} + +// Non-repr(C) unions aren't translated. +#[repr(packed)] +pub struct RustPackedUnion { + pub arg1: usize, + pub arg2: *mut u8, +} diff --git a/tests/rust/layout.toml b/tests/rust/layout.toml new file mode 100644 index 000000000..a1316dcc1 --- /dev/null +++ b/tests/rust/layout.toml @@ -0,0 +1,29 @@ +header = """ +#define CBINDGEN_PACKED __attribute__ ((packed)) +#define CBINDGEN_ALIGNED(n) __attribute__ ((aligned(n))) +""" + +[layout] +packed = "CBINDGEN_PACKED" +aligned_n = "CBINDGEN_ALIGNED" + +[export] +include = [ + "Align1Struct", + "Align2Struct", + "Align4Struct", + "Align8Struct", + "Align32Struct", + "PackedStruct", + "Align1Union", + "Align4Union", + "Align16Union", + "PackedUnion", + "UnsupportedPacked4Struct", + "UnsupportedPacked4Union", + "UnsupportedAlign4Enum", + "RustAlign4Struct", + "RustPackedStruct", + "RustAlign4Union", + "RustPackedUnion", +] diff --git a/tests/rust/layout_aligned_opaque.rs b/tests/rust/layout_aligned_opaque.rs new file mode 100644 index 000000000..c4991248a --- /dev/null +++ b/tests/rust/layout_aligned_opaque.rs @@ -0,0 +1,67 @@ +#[repr(packed, C)] +pub struct PackedStruct { + pub arg1: usize, + pub arg2: *mut u8, +} + +#[repr(packed, C)] +pub union PackedUnion { + pub variant1: usize, + pub variant2: *mut u8, +} + +// Opaque because aligned_n is not defined. +#[repr(align(1), C)] +pub union OpaqueAlign1Union { + pub variant1: usize, + pub variant2: *mut u8, +} + +// Opaque because aligned_n is not defined. +#[repr(align(4), C)] +pub union OpaqueAlign4Union { + pub variant1: usize, + pub variant2: *mut u8, +} + +// Opaque because aligned_n is not defined. +#[repr(align(16), C)] +pub union OpaqueAlign16Union { + pub variant1: usize, + pub variant2: *mut u8, +} + +// Opaque because aligned_n is not defined. +#[repr(align(1), C)] +pub struct OpaqueAlign1Struct { + pub arg1: usize, + pub arg2: *mut u8, +} + +// Opaque because aligned_n is not defined. +#[repr(align(2), C)] +pub struct OpaqueAlign2Struct { + pub arg1: usize, + pub arg2: *mut u8, +} + +// Opaque because aligned_n is not defined. +#[repr(align(4), C)] +pub struct OpaqueAlign4Struct { + pub arg1: usize, + pub arg2: *mut u8, +} + +// Opaque because aligned_n is not defined. +#[repr(align(8), C)] +pub struct OpaqueAlign8Struct { + pub arg1: usize, + pub arg2: *mut u8, +} + +// Opaque because aligned_n is not defined. +#[repr(align(32), C)] +pub struct OpaqueAlign32Struct { + pub arg1: usize, + pub arg2: *mut u8, +} diff --git a/tests/rust/layout_aligned_opaque.toml b/tests/rust/layout_aligned_opaque.toml new file mode 100644 index 000000000..1d416f155 --- /dev/null +++ b/tests/rust/layout_aligned_opaque.toml @@ -0,0 +1,22 @@ +header = """ +#define CBINDGEN_PACKED __attribute__ ((packed)) +#define CBINDGEN_ALIGNED(n) __attribute__ ((aligned(n))) +""" + +[layout] +# We do not define aligned_n. +packed = "CBINDGEN_PACKED" + +[export] +include = [ + "PackedStruct", + "PackedUnion", + "OpaqueAlign1Union", + "OpaqueAlign4Union", + "OpaqueAlign16Union", + "OpaqueAlign1Struct", + "OpaqueAlign2Struct", + "OpaqueAlign4Struct", + "OpaqueAlign8Struct", + "OpaqueAlign32Struct", +] diff --git a/tests/rust/layout_packed_opaque.rs b/tests/rust/layout_packed_opaque.rs new file mode 100644 index 000000000..d1e31c632 --- /dev/null +++ b/tests/rust/layout_packed_opaque.rs @@ -0,0 +1,61 @@ +#[repr(align(1), C)] +pub union Align1Union { + pub variant1: usize, + pub variant2: *mut u8, +} + +#[repr(align(4), C)] +pub union Align4Union { + pub variant1: usize, + pub variant2: *mut u8, +} + +#[repr(align(16), C)] +pub union Align16Union { + pub variant1: usize, + pub variant2: *mut u8, +} + +#[repr(align(1), C)] +pub struct Align1Struct { + pub arg1: usize, + pub arg2: *mut u8, +} + +#[repr(align(2), C)] +pub struct Align2Struct { + pub arg1: usize, + pub arg2: *mut u8, +} + +#[repr(align(4), C)] +pub struct Align4Struct { + pub arg1: usize, + pub arg2: *mut u8, +} + +#[repr(align(8), C)] +pub struct Align8Struct { + pub arg1: usize, + pub arg2: *mut u8, +} + +#[repr(align(32), C)] +pub struct Align32Struct { + pub arg1: usize, + pub arg2: *mut u8, +} + +// Opaque because packed is not defined. +#[repr(packed, C)] +pub struct OpaquePackedStruct { + pub arg1: usize, + pub arg2: *mut u8, +} + +// Opaque because packed is not defined. +#[repr(packed, C)] +pub union OpaquePackedUnion { + pub variant1: usize, + pub variant2: *mut u8, +} diff --git a/tests/rust/layout_packed_opaque.toml b/tests/rust/layout_packed_opaque.toml new file mode 100644 index 000000000..b72600497 --- /dev/null +++ b/tests/rust/layout_packed_opaque.toml @@ -0,0 +1,22 @@ +header = """ +#define CBINDGEN_PACKED __attribute__ ((packed)) +#define CBINDGEN_ALIGNED(n) __attribute__ ((aligned(n))) +""" + +[layout] +# We do not define packed. +aligned_n = "CBINDGEN_ALIGNED" + +[export] +include = [ + "Align1Union", + "Align4Union", + "Align16Union", + "Align1Struct", + "Align2Struct", + "Align4Struct", + "Align8Struct", + "Align32Struct", + "OpaquePackedStruct", + "OpaquePackedUnion", +]