diff --git a/src/bindgen/ir/constant.rs b/src/bindgen/ir/constant.rs index d3935749c..794e899fe 100644 --- a/src/bindgen/ir/constant.rs +++ b/src/bindgen/ir/constant.rs @@ -185,8 +185,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)?; @@ -194,28 +195,33 @@ impl Constant { return Err("Cannot have a zero sized const definition.".to_owned()); } let ty = ty.unwrap(); - if !ty.is_primitive_or_ptr_primitive() - && match item.expr { - syn::Expr::Struct(_) => false, - _ => true, - } - { - 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 can_handle_const_expr = match item.expr { + syn::Expr::Struct(_) => true, + _ => false, + }; + + if !ty.is_primitive_or_ptr_primitive() && !can_handle_const_expr { + return Err("Unhandled const definition".to_owned()); } - let impl_ty = impl_ty.unwrap(); - let struct_path = impl_ty.get_root_path().unwrap(); + let expr = Literal::load(match item.expr { + syn::Expr::Struct(syn::ExprStruct { ref fields, .. }) => { + if is_transparent && fields.len() == 1 { + &fields[0].expr + } else { + &item.expr + } + } + _ => &item.expr, + })?; + 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 9ec0ffa25..b501ce878 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}; @@ -490,6 +490,8 @@ impl Parse { mod_cfg: &Option, items: &[syn::Item], ) { + let mut impls_with_assoc_consts = Vec::new(); + for item in items { if item.has_test_attr() { continue; @@ -520,21 +522,31 @@ 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, - ); - } + let has_assoc_const = item_impl.items.iter().any(|item| match item { + syn::ImplItem::Const(_) => true, + _ => false, + }); + if has_assoc_const { + impls_with_assoc_consts.push(item_impl); } } _ => {} } } + + for item_impl in impls_with_assoc_consts { + 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. @@ -632,36 +644,93 @@ impl Parse { } } - /// Loads an associated `const` declaration - fn load_syn_assoc_const( + fn is_assoc_const_of_transparent_struct( + &self, + const_item: &syn::ImplItemConst, + ) -> Result { + let ty = match Type::load(&const_item.ty) { + Ok(Some(t)) => t, + _ => return Ok(false), + }; + let path = match ty.get_root_path() { + Some(p) => p, + _ => return Ok(false), + }; + + match self.structs.get_items(&path) { + Some(items) => { + if items.len() != 1 { + error!( + "Expected one struct to match path {}, but found {}", + path, + items.len(), + ); + return Err(()); + } + + Ok(if let ItemContainer::Struct(ref s) = items[0] { + s.is_transparent + } else { + false + }) + } + _ => Ok(false), + } + } + + /// 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_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); + for item in items.into_iter() { + let is_assoc_const_of_transparent_struct = + match self.is_assoc_const_of_transparent_struct(&item) { + Ok(b) => b, + Err(_) => continue, + }; - let full_name = constant.path.clone(); - if !self.constants.try_insert(constant) { - error!("Conflicting name for constant {}", full_name); - } + 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, + item, + mod_cfg, + is_assoc_const_of_transparent_struct, + &impl_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 fd304eefa..25faf6632 100644 --- a/tests/expectations/both/const_conflict.c +++ b/tests/expectations/both/const_conflict.c @@ -3,4 +3,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 12ad0b2c3..bdf1f6022 100644 --- a/tests/expectations/both/transparent.c +++ b/tests/expectations/both/transparent.c @@ -5,6 +5,8 @@ typedef struct DummyStruct DummyStruct; +typedef struct EnumWithAssociatedConstantInImpl EnumWithAssociatedConstantInImpl; + typedef DummyStruct TransparentComplexWrappingStructTuple; typedef uint32_t TransparentPrimitiveWrappingStructTuple; @@ -17,9 +19,19 @@ typedef DummyStruct TransparentComplexWrapper_i32; typedef uint32_t TransparentPrimitiveWrapper_i32; +typedef uint32_t TransparentPrimitiveWithAssociatedConstants; + +#define EnumWithAssociatedConstantInImpl_TEN 10 + +#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, + EnumWithAssociatedConstantInImpl h); diff --git a/tests/expectations/const_conflict.c b/tests/expectations/const_conflict.c index fd304eefa..25faf6632 100644 --- a/tests/expectations/const_conflict.c +++ b/tests/expectations/const_conflict.c @@ -3,4 +3,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 be589d5c0..3a4254ead 100644 --- a/tests/expectations/const_conflict.cpp +++ b/tests/expectations/const_conflict.cpp @@ -2,4 +2,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 fd304eefa..25faf6632 100644 --- a/tests/expectations/tag/const_conflict.c +++ b/tests/expectations/tag/const_conflict.c @@ -3,4 +3,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 e7e5dbf5a..8e5fe78da 100644 --- a/tests/expectations/tag/transparent.c +++ b/tests/expectations/tag/transparent.c @@ -5,6 +5,8 @@ struct DummyStruct; +struct EnumWithAssociatedConstantInImpl; + typedef struct DummyStruct TransparentComplexWrappingStructTuple; typedef uint32_t TransparentPrimitiveWrappingStructTuple; @@ -17,9 +19,19 @@ typedef struct DummyStruct TransparentComplexWrapper_i32; typedef uint32_t TransparentPrimitiveWrapper_i32; +typedef uint32_t TransparentPrimitiveWithAssociatedConstants; + +#define EnumWithAssociatedConstantInImpl_TEN 10 + +#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, + struct EnumWithAssociatedConstantInImpl h); diff --git a/tests/expectations/transparent.c b/tests/expectations/transparent.c index 12ad0b2c3..bdf1f6022 100644 --- a/tests/expectations/transparent.c +++ b/tests/expectations/transparent.c @@ -5,6 +5,8 @@ typedef struct DummyStruct DummyStruct; +typedef struct EnumWithAssociatedConstantInImpl EnumWithAssociatedConstantInImpl; + typedef DummyStruct TransparentComplexWrappingStructTuple; typedef uint32_t TransparentPrimitiveWrappingStructTuple; @@ -17,9 +19,19 @@ typedef DummyStruct TransparentComplexWrapper_i32; typedef uint32_t TransparentPrimitiveWrapper_i32; +typedef uint32_t TransparentPrimitiveWithAssociatedConstants; + +#define EnumWithAssociatedConstantInImpl_TEN 10 + +#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, + EnumWithAssociatedConstantInImpl h); diff --git a/tests/expectations/transparent.cpp b/tests/expectations/transparent.cpp index 2edeb522b..b134e27d0 100644 --- a/tests/expectations/transparent.cpp +++ b/tests/expectations/transparent.cpp @@ -4,6 +4,8 @@ struct DummyStruct; +struct EnumWithAssociatedConstantInImpl; + using TransparentComplexWrappingStructTuple = DummyStruct; using TransparentPrimitiveWrappingStructTuple = uint32_t; @@ -18,6 +20,14 @@ using TransparentComplexWrapper = DummyStruct; template using TransparentPrimitiveWrapper = uint32_t; +using TransparentPrimitiveWithAssociatedConstants = uint32_t; + +static const TransparentPrimitiveWrappingStructure EnumWithAssociatedConstantInImpl_TEN = 10; + +static const TransparentPrimitiveWithAssociatedConstants TransparentPrimitiveWithAssociatedConstants_ONE = 1; + +static const TransparentPrimitiveWithAssociatedConstants TransparentPrimitiveWithAssociatedConstants_ZERO = 0; + extern "C" { void root(TransparentComplexWrappingStructTuple a, @@ -25,6 +35,8 @@ void root(TransparentComplexWrappingStructTuple a, TransparentComplexWrappingStructure c, TransparentPrimitiveWrappingStructure d, TransparentComplexWrapper e, - TransparentPrimitiveWrapper f); + TransparentPrimitiveWrapper f, + TransparentPrimitiveWithAssociatedConstants g, + EnumWithAssociatedConstantInImpl h); } // extern "C" diff --git a/tests/rust/transparent.rs b/tests/rust/transparent.rs index ac8338faf..6dc77c1e4 100644 --- a/tests/rust/transparent.rs +++ b/tests/rust/transparent.rs @@ -30,6 +30,30 @@ 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 + }; +} + +enum EnumWithAssociatedConstantInImpl { A } + +impl EnumWithAssociatedConstantInImpl { + pub const TEN: TransparentPrimitiveWrappingStructure = TransparentPrimitiveWrappingStructure { only_field: 10 }; +} + #[no_mangle] pub extern "C" fn root( a: TransparentComplexWrappingStructTuple, @@ -38,4 +62,6 @@ pub extern "C" fn root( d: TransparentPrimitiveWrappingStructure, e: TransparentComplexWrapper, f: TransparentPrimitiveWrapper, + g: TransparentPrimitiveWithAssociatedConstants, + h: EnumWithAssociatedConstantInImpl, ) { }