diff options
author | Emilio Cobos Álvarez <emilio@crisal.io> | 2021-04-03 12:57:19 +0200 |
---|---|---|
committer | Emilio Cobos Álvarez <emilio@crisal.io> | 2021-04-03 13:05:04 +0200 |
commit | 4faaf9a5f3962f1548824cb42fb8559dc6baac7d (patch) | |
tree | e1fadf196fba1da7a4152aa40a95bbb1e8a8472e | |
parent | b21086cc3ba5aaeea53082e0618733a1b354daab (diff) |
codegen: Deal with overloads in method code generation.
Fixes #2019
-rw-r--r-- | src/codegen/mod.rs | 99 | ||||
-rw-r--r-- | tests/expectations/tests/issue-2019.rs | 73 | ||||
-rw-r--r-- | tests/headers/issue-2019.hpp | 10 |
3 files changed, 151 insertions, 31 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 95162204..e62b1a87 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -422,37 +422,36 @@ trait CodeGenerator { /// Extra information from the caller. type Extra; + /// Extra information returned to the caller. + type Return; + fn codegen<'a>( &self, ctx: &BindgenContext, result: &mut CodegenResult<'a>, extra: &Self::Extra, - ); + ) -> Self::Return; } -impl CodeGenerator for Item { - type Extra = (); - - fn codegen<'a>( +impl Item { + fn process_before_codegen( &self, ctx: &BindgenContext, - result: &mut CodegenResult<'a>, - _extra: &(), - ) { + result: &mut CodegenResult, + ) -> bool { if !self.is_enabled_for_codegen(ctx) { - return; + return false; } if self.is_blocklisted(ctx) || result.seen(self.id()) { debug!( - "<Item as CodeGenerator>::codegen: Ignoring hidden or seen: \ + "<Item as CodeGenerator>::process_before_codegen: Ignoring hidden or seen: \ self = {:?}", self ); - return; + return false; } - debug!("<Item as CodeGenerator>::codegen: self = {:?}", self); if !ctx.codegen_items().contains(&self.id()) { // TODO(emilio, #453): Figure out what to do when this happens // legitimately, we could track the opaque stuff and disable the @@ -461,6 +460,24 @@ impl CodeGenerator for Item { } result.set_seen(self.id()); + true + } +} + +impl CodeGenerator for Item { + type Extra = (); + type Return = (); + + fn codegen<'a>( + &self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + _extra: &(), + ) { + debug!("<Item as CodeGenerator>::codegen: self = {:?}", self); + if !self.process_before_codegen(ctx, result) { + return; + } match *self.kind() { ItemKind::Module(ref module) => { @@ -481,6 +498,7 @@ impl CodeGenerator for Item { impl CodeGenerator for Module { type Extra = Item; + type Return = (); fn codegen<'a>( &self, @@ -572,6 +590,8 @@ impl CodeGenerator for Module { impl CodeGenerator for Var { type Extra = Item; + type Return = (); + fn codegen<'a>( &self, ctx: &BindgenContext, @@ -698,6 +718,7 @@ impl CodeGenerator for Var { impl CodeGenerator for Type { type Extra = Item; + type Return = (); fn codegen<'a>( &self, @@ -1004,6 +1025,7 @@ impl<'a> Vtable<'a> { impl<'a> CodeGenerator for Vtable<'a> { type Extra = Item; + type Return = (); fn codegen<'b>( &self, @@ -1048,6 +1070,7 @@ impl<'a> TryToRustTy for Vtable<'a> { impl CodeGenerator for TemplateInstantiation { type Extra = Item; + type Return = (); fn codegen<'a>( &self, @@ -1664,6 +1687,7 @@ impl<'a> FieldCodegen<'a> for Bitfield { impl CodeGenerator for CompInfo { type Extra = Item; + type Return = (); fn codegen<'a>( &self, @@ -2261,13 +2285,15 @@ impl MethodCodegen for Method { // First of all, output the actual function. let function_item = ctx.resolve_item(self.signature()); - if function_item.is_blocklisted(ctx) { - // We shouldn't emit a method declaration if the function is blocklisted + if !function_item.process_before_codegen(ctx, result) { return; } - function_item.codegen(ctx, result, &()); - let function = function_item.expect_function(); + let times_seen = function.codegen(ctx, result, &function_item); + let times_seen = match times_seen { + Some(seen) => seen, + None => return, + }; let signature_item = ctx.resolve_item(function.signature()); let mut name = match self.kind() { MethodKind::Constructor => "new".into(), @@ -2302,7 +2328,11 @@ impl MethodCodegen for Method { name.push_str(&count.to_string()); } - let function_name = ctx.rust_ident(function_item.canonical_name(ctx)); + let mut function_name = function_item.canonical_name(ctx); + if times_seen > 0 { + write!(&mut function_name, "{}", times_seen).unwrap(); + } + let function_name = ctx.rust_ident(function_name); let mut args = utils::fnsig_arguments(ctx, signature); let mut ret = utils::fnsig_return_ty(ctx, signature); @@ -2808,6 +2838,7 @@ impl<'a> EnumBuilder<'a> { impl CodeGenerator for Enum { type Extra = Item; + type Return = (); fn codegen<'a>( &self, @@ -3731,19 +3762,23 @@ impl TryToRustTy for FunctionSig { impl CodeGenerator for Function { type Extra = Item; + /// If we've actually generated the symbol, the number of times we've seen + /// it. + type Return = Option<u32>; + fn codegen<'a>( &self, ctx: &BindgenContext, result: &mut CodegenResult<'a>, item: &Item, - ) { + ) -> Self::Return { debug!("<Function as CodeGenerator>::codegen: item = {:?}", item); debug_assert!(item.is_enabled_for_codegen(ctx)); // We can't currently do anything with Internal functions so just // avoid generating anything for them. match self.linkage() { - Linkage::Internal => return, + Linkage::Internal => return None, Linkage::External => {} } @@ -3753,7 +3788,7 @@ impl CodeGenerator for Function { FunctionKind::Method(ref method_kind) if method_kind.is_pure_virtual() => { - return; + return None; } _ => {} } @@ -3763,7 +3798,7 @@ impl CodeGenerator for Function { // instantiations is open ended and we have no way of knowing which // monomorphizations actually exist. if !item.all_template_params(ctx).is_empty() { - return; + return None; } let name = self.name(); @@ -3776,7 +3811,7 @@ impl CodeGenerator for Function { // TODO: Maybe warn here if there's a type/argument mismatch, or // something? if result.seen_function(seen_symbol_name) { - return; + return None; } result.saw_function(seen_symbol_name); } @@ -3803,21 +3838,14 @@ impl CodeGenerator for Function { attributes.push(attributes::doc(comment)); } - // Handle overloaded functions by giving each overload its own unique - // suffix. - let times_seen = result.overload_number(&canonical_name); - if times_seen > 0 { - write!(&mut canonical_name, "{}", times_seen).unwrap(); - } - let abi = match signature.abi() { Abi::ThisCall if !ctx.options().rust_features().thiscall_abi => { warn!("Skipping function with thiscall ABI that isn't supported by the configured Rust target"); - return; + return None; } Abi::Win64 if signature.is_variadic() => { warn!("Skipping variadic function with Win64 ABI that isn't supported"); - return; + return None; } Abi::Unknown(unknown_abi) => { panic!( @@ -3828,6 +3856,13 @@ impl CodeGenerator for Function { abi => abi, }; + // Handle overloaded functions by giving each overload its own unique + // suffix. + let times_seen = result.overload_number(&canonical_name); + if times_seen > 0 { + write!(&mut canonical_name, "{}", times_seen).unwrap(); + } + let link_name = mangled_name.unwrap_or(name); if !utils::names_will_be_identical_after_mangling( &canonical_name, @@ -3878,6 +3913,7 @@ impl CodeGenerator for Function { } else { result.push(tokens); } + Some(times_seen) } } @@ -3933,6 +3969,7 @@ fn objc_method_codegen( impl CodeGenerator for ObjCInterface { type Extra = Item; + type Return = (); fn codegen<'a>( &self, diff --git a/tests/expectations/tests/issue-2019.rs b/tests/expectations/tests/issue-2019.rs new file mode 100644 index 00000000..383bd57e --- /dev/null +++ b/tests/expectations/tests/issue-2019.rs @@ -0,0 +1,73 @@ +#![allow( + dead_code, + non_snake_case, + non_camel_case_types, + non_upper_case_globals +)] + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct A { + pub a: ::std::os::raw::c_int, +} +#[test] +fn bindgen_test_layout_A() { + assert_eq!( + ::std::mem::size_of::<A>(), + 4usize, + concat!("Size of: ", stringify!(A)) + ); + assert_eq!( + ::std::mem::align_of::<A>(), + 4usize, + concat!("Alignment of ", stringify!(A)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<A>())).a as *const _ as usize }, + 0usize, + concat!("Offset of field: ", stringify!(A), "::", stringify!(a)) + ); +} +extern "C" { + #[link_name = "\u{1}_ZN1A4makeEv"] + pub fn make() -> A; +} +impl A { + #[inline] + pub unsafe fn make() -> A { + make() + } +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct B { + pub b: ::std::os::raw::c_int, +} +#[test] +fn bindgen_test_layout_B() { + assert_eq!( + ::std::mem::size_of::<B>(), + 4usize, + concat!("Size of: ", stringify!(B)) + ); + assert_eq!( + ::std::mem::align_of::<B>(), + 4usize, + concat!("Alignment of ", stringify!(B)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<B>())).b as *const _ as usize }, + 0usize, + concat!("Offset of field: ", stringify!(B), "::", stringify!(b)) + ); +} +extern "C" { + #[link_name = "\u{1}_ZN1B4makeEv"] + pub fn make1() -> B; +} +impl B { + #[inline] + pub unsafe fn make() -> B { + make1() + } +} diff --git a/tests/headers/issue-2019.hpp b/tests/headers/issue-2019.hpp new file mode 100644 index 00000000..2e9a3ffd --- /dev/null +++ b/tests/headers/issue-2019.hpp @@ -0,0 +1,10 @@ +// bindgen-flags: --disable-nested-struct-naming + +struct A { + static A make(); + int a; +}; +struct B { + static B make(); + int b; +}; |