summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmilio Cobos Álvarez <emilio@crisal.io>2021-04-03 12:57:19 +0200
committerEmilio Cobos Álvarez <emilio@crisal.io>2021-04-03 13:05:04 +0200
commit4faaf9a5f3962f1548824cb42fb8559dc6baac7d (patch)
treee1fadf196fba1da7a4152aa40a95bbb1e8a8472e
parentb21086cc3ba5aaeea53082e0618733a1b354daab (diff)
codegen: Deal with overloads in method code generation.
Fixes #2019
-rw-r--r--src/codegen/mod.rs99
-rw-r--r--tests/expectations/tests/issue-2019.rs73
-rw-r--r--tests/headers/issue-2019.hpp10
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;
+};