codegen: Deal with overloads in method code generation.

Fixes #2019
This commit is contained in:
Emilio Cobos Álvarez 2021-04-03 12:57:19 +02:00
parent b21086cc3b
commit 4faaf9a5f3
3 changed files with 151 additions and 31 deletions

View File

@ -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,

View File

@ -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()
}
}

View File

@ -0,0 +1,10 @@
// bindgen-flags: --disable-nested-struct-naming
struct A {
static A make();
int a;
};
struct B {
static B make();
int b;
};