diff --git a/src/bindgen/ir/constant.rs b/src/bindgen/ir/constant.rs index 6b1aa3ebd..8a8321109 100644 --- a/src/bindgen/ir/constant.rs +++ b/src/bindgen/ir/constant.rs @@ -184,8 +184,9 @@ impl Constant { pub fn load_assoc( name: String, item: &syn::ImplItemConst, - impl_ty: &syn::Type, mod_cfg: &Option, + is_transparent: bool, + struct_path: &Path, ) -> Result { let ty = Type::load(&item.ty)?; @@ -201,19 +202,24 @@ impl Constant { return Err("Unhanded const definition".to_owned()); } - let impl_ty = Type::load(impl_ty)?; - if impl_ty.is_none() { - return Err("impl has an empty type".to_owned()); - } - let impl_ty = impl_ty.unwrap(); + let expr = Literal::load( + if let syn::Expr::Struct(syn::ExprStruct { ref fields, .. }) = item.expr { + if is_transparent && fields.len() == 1 { + &fields[0].expr + } else { + &item.expr + } + } else { + &item.expr + }, + )?; - let struct_path = impl_ty.get_root_path().unwrap(); let full_name = Path::new(format!("{}_{}", struct_path, name)); Ok(Constant::new( full_name, ty, - Literal::load(&item.expr)?, + expr, Cfg::append(mod_cfg, Cfg::load(&item.attrs)), AnnotationSet::load(&item.attrs)?, Documentation::load(&item.attrs), diff --git a/src/bindgen/parser.rs b/src/bindgen/parser.rs index e6fdf478f..392165004 100644 --- a/src/bindgen/parser.rs +++ b/src/bindgen/parser.rs @@ -12,8 +12,8 @@ use syn; use bindgen::cargo::{Cargo, PackageRef}; use bindgen::error::Error; use bindgen::ir::{ - AnnotationSet, Cfg, Constant, Documentation, Enum, Function, GenericParams, ItemMap, - OpaqueItem, Path, Static, Struct, Typedef, Union, + AnnotationSet, Cfg, Constant, Documentation, Enum, Function, GenericParams, ItemContainer, + ItemMap, OpaqueItem, Path, Static, Struct, Type, Typedef, Union, }; use bindgen::utilities::{SynAbiHelpers, SynItemHelpers}; @@ -494,6 +494,8 @@ impl Parse { mod_cfg: &Option, items: &[syn::Item], ) { + let mut impls = Vec::new(); + for item in items { if item.has_test_attr() { continue; @@ -524,21 +526,25 @@ impl Parse { self.load_syn_ty(crate_name, mod_cfg, item); } syn::Item::Impl(ref item_impl) => { - for item in &item_impl.items { - if let syn::ImplItem::Const(ref item) = item { - self.load_syn_assoc_const( - binding_crate_name, - crate_name, - mod_cfg, - &item_impl.self_ty, - item, - ); - } - } + impls.push(item_impl); } _ => {} } } + + for item_impl in impls { + let associated_constants = item_impl.items.iter().filter_map(|item| match item { + syn::ImplItem::Const(ref associated_constant) => Some(associated_constant), + _ => None, + }); + self.load_syn_assoc_consts( + binding_crate_name, + crate_name, + mod_cfg, + &item_impl.self_ty, + associated_constants, + ); + } } /// Enters a `extern "C" { }` declaration and loads function declarations. @@ -636,36 +642,80 @@ impl Parse { } } - /// Loads an associated `const` declaration - fn load_syn_assoc_const( + /// Loads associated `const` declarations + fn load_syn_assoc_consts<'a, I>( &mut self, binding_crate_name: &str, crate_name: &str, mod_cfg: &Option, impl_ty: &syn::Type, - item: &syn::ImplItemConst, - ) { - if crate_name != binding_crate_name { - info!( - "Skip {}::{} - (const's outside of the binding crate are not used).", - crate_name, &item.ident - ); + items: I, + ) where + I: IntoIterator, + { + let ty = Type::load(&impl_ty).unwrap(); + if ty.is_none() { return; } - let const_name = item.ident.to_string(); + let impl_struct_path = ty.unwrap().get_root_path().unwrap(); - match Constant::load_assoc(const_name.clone(), item, impl_ty, mod_cfg) { - Ok(constant) => { - info!("Take {}::{}.", crate_name, &item.ident); + let is_transparent = if let Some(ref impl_items) = self.structs.get_items(&impl_struct_path) + { + if impl_items.len() != 1 { + error!( + "Expected one struct to match path {}, but found {}", + impl_struct_path, + impl_items.len() + ); + return; + } + if let ItemContainer::Struct(ref s) = impl_items[0] { + s.is_transparent + } else { + info!( + "Skip impl block for {}::{} (impl blocks for associated constants are only defined for structs).", + crate_name, impl_struct_path + ); + return; + } + } else { + error!( + "Cannot find type for {}::{} (impl blocks require the struct declaration to be known).", + crate_name, impl_struct_path + ); + return; + }; - let full_name = constant.path.clone(); - if !self.constants.try_insert(constant) { - error!("Conflicting name for constant {}", full_name); - } + for item in items.into_iter() { + if crate_name != binding_crate_name { + info!( + "Skip {}::{} - (const's outside of the binding crate are not used).", + crate_name, &item.ident + ); + continue; } - Err(msg) => { - warn!("Skip {}::{} - ({})", crate_name, &item.ident, msg); + + let const_name = item.ident.to_string(); + + match Constant::load_assoc( + const_name.clone(), + item, + mod_cfg, + is_transparent, + &impl_struct_path, + ) { + Ok(constant) => { + info!("Take {}::{}.", crate_name, &item.ident); + + let full_name = constant.path.clone(); + if !self.constants.try_insert(constant) { + error!("Conflicting name for constant {}", full_name); + } + } + Err(msg) => { + warn!("Skip {}::{} - ({})", crate_name, &item.ident, msg); + } } } } diff --git a/tests/expectations/both/const_conflict.c b/tests/expectations/both/const_conflict.c index 707751ed2..2e6ccb42c 100644 --- a/tests/expectations/both/const_conflict.c +++ b/tests/expectations/both/const_conflict.c @@ -2,4 +2,4 @@ #include #include -#define Foo_FOO 0 +#define Foo_FOO 42 diff --git a/tests/expectations/both/transparent.c b/tests/expectations/both/transparent.c index b584ce70a..875aa3fc5 100644 --- a/tests/expectations/both/transparent.c +++ b/tests/expectations/both/transparent.c @@ -16,9 +16,16 @@ typedef DummyStruct TransparentComplexWrapper_i32; typedef uint32_t TransparentPrimitiveWrapper_i32; +typedef uint32_t TransparentPrimitiveWithAssociatedConstants; + +#define TransparentPrimitiveWithAssociatedConstants_ONE 1 + +#define TransparentPrimitiveWithAssociatedConstants_ZERO 0 + void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrappingStructTuple b, TransparentComplexWrappingStructure c, TransparentPrimitiveWrappingStructure d, TransparentComplexWrapper_i32 e, - TransparentPrimitiveWrapper_i32 f); + TransparentPrimitiveWrapper_i32 f, + TransparentPrimitiveWithAssociatedConstants g); diff --git a/tests/expectations/const_conflict.c b/tests/expectations/const_conflict.c index 707751ed2..2e6ccb42c 100644 --- a/tests/expectations/const_conflict.c +++ b/tests/expectations/const_conflict.c @@ -2,4 +2,4 @@ #include #include -#define Foo_FOO 0 +#define Foo_FOO 42 diff --git a/tests/expectations/const_conflict.cpp b/tests/expectations/const_conflict.cpp index 18493dab3..0aa69acbc 100644 --- a/tests/expectations/const_conflict.cpp +++ b/tests/expectations/const_conflict.cpp @@ -1,4 +1,4 @@ #include #include -static const int32_t Foo_FOO = 0; +static const uint32_t Foo_FOO = 42; diff --git a/tests/expectations/tag/const_conflict.c b/tests/expectations/tag/const_conflict.c index 707751ed2..2e6ccb42c 100644 --- a/tests/expectations/tag/const_conflict.c +++ b/tests/expectations/tag/const_conflict.c @@ -2,4 +2,4 @@ #include #include -#define Foo_FOO 0 +#define Foo_FOO 42 diff --git a/tests/expectations/tag/transparent.c b/tests/expectations/tag/transparent.c index 98d85ee75..54c9f032f 100644 --- a/tests/expectations/tag/transparent.c +++ b/tests/expectations/tag/transparent.c @@ -16,9 +16,16 @@ typedef struct DummyStruct TransparentComplexWrapper_i32; typedef uint32_t TransparentPrimitiveWrapper_i32; +typedef uint32_t TransparentPrimitiveWithAssociatedConstants; + +#define TransparentPrimitiveWithAssociatedConstants_ONE 1 + +#define TransparentPrimitiveWithAssociatedConstants_ZERO 0 + void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrappingStructTuple b, TransparentComplexWrappingStructure c, TransparentPrimitiveWrappingStructure d, TransparentComplexWrapper_i32 e, - TransparentPrimitiveWrapper_i32 f); + TransparentPrimitiveWrapper_i32 f, + TransparentPrimitiveWithAssociatedConstants g); diff --git a/tests/expectations/transparent.c b/tests/expectations/transparent.c index b584ce70a..875aa3fc5 100644 --- a/tests/expectations/transparent.c +++ b/tests/expectations/transparent.c @@ -16,9 +16,16 @@ typedef DummyStruct TransparentComplexWrapper_i32; typedef uint32_t TransparentPrimitiveWrapper_i32; +typedef uint32_t TransparentPrimitiveWithAssociatedConstants; + +#define TransparentPrimitiveWithAssociatedConstants_ONE 1 + +#define TransparentPrimitiveWithAssociatedConstants_ZERO 0 + void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrappingStructTuple b, TransparentComplexWrappingStructure c, TransparentPrimitiveWrappingStructure d, TransparentComplexWrapper_i32 e, - TransparentPrimitiveWrapper_i32 f); + TransparentPrimitiveWrapper_i32 f, + TransparentPrimitiveWithAssociatedConstants g); diff --git a/tests/expectations/transparent.cpp b/tests/expectations/transparent.cpp index 656876a39..0570a3751 100644 --- a/tests/expectations/transparent.cpp +++ b/tests/expectations/transparent.cpp @@ -17,6 +17,12 @@ using TransparentComplexWrapper = DummyStruct; template using TransparentPrimitiveWrapper = uint32_t; +using TransparentPrimitiveWithAssociatedConstants = uint32_t; + +static const TransparentPrimitiveWithAssociatedConstants TransparentPrimitiveWithAssociatedConstants_ONE = 1; + +static const TransparentPrimitiveWithAssociatedConstants TransparentPrimitiveWithAssociatedConstants_ZERO = 0; + extern "C" { void root(TransparentComplexWrappingStructTuple a, @@ -24,6 +30,7 @@ void root(TransparentComplexWrappingStructTuple a, TransparentComplexWrappingStructure c, TransparentPrimitiveWrappingStructure d, TransparentComplexWrapper e, - TransparentPrimitiveWrapper f); + TransparentPrimitiveWrapper f, + TransparentPrimitiveWithAssociatedConstants g); } // extern "C" diff --git a/tests/rust/transparent.rs b/tests/rust/transparent.rs index ac8338faf..0060592f0 100644 --- a/tests/rust/transparent.rs +++ b/tests/rust/transparent.rs @@ -30,6 +30,24 @@ struct TransparentPrimitiveWrapper { marker: PhantomData, } +// Associated constant declared before struct declaration. +impl TransparentPrimitiveWithAssociatedConstants { + pub const ZERO: TransparentPrimitiveWithAssociatedConstants = TransparentPrimitiveWithAssociatedConstants { + bits: 0 + }; +} + +// Transparent structure wrapping a primitive with associated constants. +#[repr(transparent)] +struct TransparentPrimitiveWithAssociatedConstants { bits: u32 } + +// Associated constant declared after struct declaration. +impl TransparentPrimitiveWithAssociatedConstants { + pub const ONE: TransparentPrimitiveWithAssociatedConstants = TransparentPrimitiveWithAssociatedConstants { + bits: 1 + }; +} + #[no_mangle] pub extern "C" fn root( a: TransparentComplexWrappingStructTuple, @@ -38,4 +56,5 @@ pub extern "C" fn root( d: TransparentPrimitiveWrappingStructure, e: TransparentComplexWrapper, f: TransparentPrimitiveWrapper, + g: TransparentPrimitiveWithAssociatedConstants, ) { }