From 7c97da1020c33b200039dd155237c8dc2da49c0b Mon Sep 17 00:00:00 2001 From: Joshua Groves Date: Tue, 8 Jan 2019 13:01:03 -0700 Subject: [PATCH] Handle enum associated constants and reduce memory usage --- src/bindgen/ir/constant.rs | 31 +++++---- src/bindgen/parser.rs | 93 ++++++++++++++++----------- tests/expectations/both/transparent.c | 7 +- tests/expectations/tag/transparent.c | 7 +- tests/expectations/transparent.c | 7 +- tests/expectations/transparent.cpp | 7 +- tests/rust/transparent.rs | 7 ++ 7 files changed, 104 insertions(+), 55 deletions(-) diff --git a/src/bindgen/ir/constant.rs b/src/bindgen/ir/constant.rs index 76670daeb..fee0c4ad0 100644 --- a/src/bindgen/ir/constant.rs +++ b/src/bindgen/ir/constant.rs @@ -195,25 +195,28 @@ 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, - } + + 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("Unhanded const definition".to_owned()); + return Err("Unhandled const definition".to_owned()); } 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 + match item.expr { + syn::Expr::Struct(syn::ExprStruct { ref fields, .. }) => { + if is_transparent && fields.len() == 1 { + &fields[0].expr + } else { + &item.expr + } } - } else { - &item.expr - }, + _ => &item.expr, + } )?; let full_name = Path::new(format!("{}_{}", struct_path, name)); diff --git a/src/bindgen/parser.rs b/src/bindgen/parser.rs index 4173444f7..ab728abc2 100644 --- a/src/bindgen/parser.rs +++ b/src/bindgen/parser.rs @@ -490,7 +490,7 @@ impl Parse { mod_cfg: &Option, items: &[syn::Item], ) { - let mut impls = Vec::new(); + let mut impls_with_assoc_consts = Vec::new(); for item in items { if item.has_test_attr() { @@ -522,17 +522,27 @@ impl Parse { self.load_syn_ty(crate_name, mod_cfg, item); } syn::Item::Impl(ref item_impl) => { - impls.push(item_impl); + 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 { - let associated_constants = item_impl.items.iter().filter_map(|item| match item { - syn::ImplItem::Const(ref associated_constant) => Some(associated_constant), - _ => None, - }); + 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, @@ -638,6 +648,37 @@ impl Parse { } } + 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, @@ -654,36 +695,14 @@ impl Parse { return; } - let impl_struct_path = ty.unwrap().get_root_path().unwrap(); - - 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 impl_path = ty.unwrap().get_root_path().unwrap(); 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, + }; + if crate_name != binding_crate_name { info!( "Skip {}::{} - (const's outside of the binding crate are not used).", @@ -698,8 +717,8 @@ impl Parse { const_name.clone(), item, mod_cfg, - is_transparent, - &impl_struct_path, + is_assoc_const_of_transparent_struct, + &impl_path, ) { Ok(constant) => { info!("Take {}::{}.", crate_name, &item.ident); diff --git a/tests/expectations/both/transparent.c b/tests/expectations/both/transparent.c index 8a59a7435..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; @@ -19,6 +21,8 @@ typedef uint32_t TransparentPrimitiveWrapper_i32; typedef uint32_t TransparentPrimitiveWithAssociatedConstants; +#define EnumWithAssociatedConstantInImpl_TEN 10 + #define TransparentPrimitiveWithAssociatedConstants_ONE 1 #define TransparentPrimitiveWithAssociatedConstants_ZERO 0 @@ -29,4 +33,5 @@ void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrappingStructure d, TransparentComplexWrapper_i32 e, TransparentPrimitiveWrapper_i32 f, - TransparentPrimitiveWithAssociatedConstants g); + TransparentPrimitiveWithAssociatedConstants g, + EnumWithAssociatedConstantInImpl h); diff --git a/tests/expectations/tag/transparent.c b/tests/expectations/tag/transparent.c index 37743a44f..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; @@ -19,6 +21,8 @@ typedef uint32_t TransparentPrimitiveWrapper_i32; typedef uint32_t TransparentPrimitiveWithAssociatedConstants; +#define EnumWithAssociatedConstantInImpl_TEN 10 + #define TransparentPrimitiveWithAssociatedConstants_ONE 1 #define TransparentPrimitiveWithAssociatedConstants_ZERO 0 @@ -29,4 +33,5 @@ void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrappingStructure d, TransparentComplexWrapper_i32 e, TransparentPrimitiveWrapper_i32 f, - TransparentPrimitiveWithAssociatedConstants g); + TransparentPrimitiveWithAssociatedConstants g, + struct EnumWithAssociatedConstantInImpl h); diff --git a/tests/expectations/transparent.c b/tests/expectations/transparent.c index 8a59a7435..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; @@ -19,6 +21,8 @@ typedef uint32_t TransparentPrimitiveWrapper_i32; typedef uint32_t TransparentPrimitiveWithAssociatedConstants; +#define EnumWithAssociatedConstantInImpl_TEN 10 + #define TransparentPrimitiveWithAssociatedConstants_ONE 1 #define TransparentPrimitiveWithAssociatedConstants_ZERO 0 @@ -29,4 +33,5 @@ void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrappingStructure d, TransparentComplexWrapper_i32 e, TransparentPrimitiveWrapper_i32 f, - TransparentPrimitiveWithAssociatedConstants g); + TransparentPrimitiveWithAssociatedConstants g, + EnumWithAssociatedConstantInImpl h); diff --git a/tests/expectations/transparent.cpp b/tests/expectations/transparent.cpp index ac609944e..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; @@ -20,6 +22,8 @@ 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; @@ -32,6 +36,7 @@ void root(TransparentComplexWrappingStructTuple a, TransparentPrimitiveWrappingStructure d, TransparentComplexWrapper e, TransparentPrimitiveWrapper f, - TransparentPrimitiveWithAssociatedConstants g); + TransparentPrimitiveWithAssociatedConstants g, + EnumWithAssociatedConstantInImpl h); } // extern "C" diff --git a/tests/rust/transparent.rs b/tests/rust/transparent.rs index 0060592f0..6dc77c1e4 100644 --- a/tests/rust/transparent.rs +++ b/tests/rust/transparent.rs @@ -48,6 +48,12 @@ impl TransparentPrimitiveWithAssociatedConstants { }; } +enum EnumWithAssociatedConstantInImpl { A } + +impl EnumWithAssociatedConstantInImpl { + pub const TEN: TransparentPrimitiveWrappingStructure = TransparentPrimitiveWrappingStructure { only_field: 10 }; +} + #[no_mangle] pub extern "C" fn root( a: TransparentComplexWrappingStructTuple, @@ -57,4 +63,5 @@ pub extern "C" fn root( e: TransparentComplexWrapper, f: TransparentPrimitiveWrapper, g: TransparentPrimitiveWithAssociatedConstants, + h: EnumWithAssociatedConstantInImpl, ) { }