Skip to content

Commit

Permalink
Add attribute for C++ special members.
Browse files Browse the repository at this point in the history
See google/autocxx#456 for details.

If I was submitting this upstream, I would have put the information
about special members directly in the MethodKind enum, but that would
have been a pretty invasive change that could cause merge conflicts when
merging from upstream. I've therefore decided to put add a separate enum
that is used in as few places as possible.
  • Loading branch information
martinboehme committed Apr 29, 2021
1 parent 33e5e16 commit 388d43a
Show file tree
Hide file tree
Showing 17 changed files with 169 additions and 3 deletions.
15 changes: 15 additions & 0 deletions src/clang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,21 @@ impl Cursor {
unsafe { clang_isVirtualBase(self.x) != 0 }
}

// Is this cursor's referent a default constructor?
pub fn is_default_constructor(&self) -> bool {
unsafe { clang_CXXConstructor_isDefaultConstructor(self.x) != 0 }
}

// Is this cursor's referent a copy constructor?
pub fn is_copy_constructor(&self) -> bool {
unsafe { clang_CXXConstructor_isCopyConstructor(self.x) != 0 }
}

// Is this cursor's referent a move constructor?
pub fn is_move_constructor(&self) -> bool {
unsafe { clang_CXXConstructor_isMoveConstructor(self.x) != 0 }
}

/// Try to evaluate this cursor.
pub fn evaluate(&self) -> Option<EvalResult> {
EvalResult::new(*self)
Expand Down
13 changes: 13 additions & 0 deletions src/codegen/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use proc_macro2::{Ident, Span, TokenStream};
use quote::TokenStreamExt;

pub mod attributes {
use crate::ir::comp::SpecialMemberKind;
use proc_macro2::{Ident, Span, TokenStream};
use std::str::FromStr;

Expand Down Expand Up @@ -104,6 +105,18 @@ pub mod attributes {
#[bindgen_unused_template_param]
}
}

pub fn special_member(kind: SpecialMemberKind) -> TokenStream {
let kind_str = match kind {
SpecialMemberKind::DefaultConstructor => "default_ctor",
SpecialMemberKind::CopyConstructor => "copy_ctor",
SpecialMemberKind::MoveConstructor => "move_ctor",
SpecialMemberKind::Destructor => "dtor",
};
quote! {
#[bindgen_special_member(#kind_str)]
}
}
}

/// Generates a proper type for a field or type with a given `Layout`, that is,
Expand Down
4 changes: 4 additions & 0 deletions src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3977,6 +3977,10 @@ impl CodeGenerator for Function {
attributes.push(attributes::original_name(self.name()));
}

if let Some(special_member_kind) = self.special_member() {
attributes.push(attributes::special_member(special_member_kind));
}

let link_name = mangled_name.unwrap_or(name);
if !utils::names_will_be_identical_after_mangling(
&canonical_name,
Expand Down
11 changes: 11 additions & 0 deletions src/ir/comp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,17 @@ impl MethodKind {
}
}

// The kind of C++ special member.
// TODO: We don't currently cover copy assignment or move assignment operator
// because libclang doesn't provide a way to query for them.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum SpecialMemberKind {
DefaultConstructor,
CopyConstructor,
MoveConstructor,
Destructor,
}

/// A struct representing a C++ method, either static, normal, or virtual.
#[derive(Debug)]
pub struct Method {
Expand Down
35 changes: 32 additions & 3 deletions src/ir/function.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Intermediate representation for C/C++ functions and methods.
use super::comp::MethodKind;
use super::comp::{MethodKind, SpecialMemberKind};
use super::context::{BindgenContext, TypeId};
use super::dot::DotAttributes;
use super::item::Item;
Expand Down Expand Up @@ -92,6 +92,9 @@ pub struct Function {

/// The linkage of the function.
linkage: Linkage,

/// C++ special member kind, if any.
special_member: Option<SpecialMemberKind>,
}

impl Function {
Expand All @@ -103,6 +106,7 @@ impl Function {
comment: Option<String>,
kind: FunctionKind,
linkage: Linkage,
special_member: Option<SpecialMemberKind>,
) -> Self {
Function {
name,
Expand All @@ -111,6 +115,7 @@ impl Function {
comment,
kind,
linkage,
special_member,
}
}

Expand Down Expand Up @@ -138,6 +143,11 @@ impl Function {
pub fn linkage(&self) -> Linkage {
self.linkage
}

/// Get this function's C++ special member kind.
pub fn special_member(&self) -> Option<SpecialMemberKind> {
self.special_member
}
}

impl DotAttributes for Function {
Expand Down Expand Up @@ -631,8 +641,27 @@ impl ClangSubItemParser for Function {
let mangled_name = cursor_mangling(context, &cursor);
let comment = cursor.raw_comment();

let function =
Self::new(name, mangled_name, sig, comment, kind, linkage);
let special_member = if cursor.is_default_constructor() {
Some(SpecialMemberKind::DefaultConstructor)
} else if cursor.is_copy_constructor() {
Some(SpecialMemberKind::CopyConstructor)
} else if cursor.is_move_constructor() {
Some(SpecialMemberKind::MoveConstructor)
} else if cursor.kind() == clang_sys::CXCursor_Destructor {
Some(SpecialMemberKind::Destructor)
} else {
None
};

let function = Self::new(
name,
mangled_name,
sig,
comment,
kind,
linkage,
special_member,
);
Ok(ParseResult::New(function, Some(cursor)))
}
}
Expand Down
1 change: 1 addition & 0 deletions tests/expectations/tests/constructor-tp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ fn bindgen_test_layout_Bar() {
}
extern "C" {
#[bindgen_original_name("Bar")]
#[bindgen_special_member("default_ctor")]
#[link_name = "\u{1}_ZN3BarC1Ev"]
pub fn Bar_Bar(this: *mut Bar);
}
Expand Down
1 change: 1 addition & 0 deletions tests/expectations/tests/constructors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ fn bindgen_test_layout_TestPublicNoArgs() {
}
extern "C" {
#[bindgen_original_name("TestPublicNoArgs")]
#[bindgen_special_member("default_ctor")]
#[link_name = "\u{1}_ZN16TestPublicNoArgsC1Ev"]
pub fn TestPublicNoArgs_TestPublicNoArgs(this: *mut TestPublicNoArgs);
}
Expand Down
1 change: 1 addition & 0 deletions tests/expectations/tests/constructors_1_33.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ fn bindgen_test_layout_TestPublicNoArgs() {
}
extern "C" {
#[bindgen_original_name("TestPublicNoArgs")]
#[bindgen_special_member("default_ctor")]
#[link_name = "\u{1}_ZN16TestPublicNoArgsC1Ev"]
pub fn TestPublicNoArgs_TestPublicNoArgs(this: *mut TestPublicNoArgs);
}
Expand Down
1 change: 1 addition & 0 deletions tests/expectations/tests/gen-destructors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ fn bindgen_test_layout_Foo() {
}
extern "C" {
#[bindgen_original_name("Foo_destructor")]
#[bindgen_special_member("dtor")]
#[link_name = "\u{1}_ZN3FooD1Ev"]
pub fn Foo_Foo_destructor(this: *mut Foo);
}
Expand Down
1 change: 1 addition & 0 deletions tests/expectations/tests/issue-1197-pure-virtual-stuff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ extern "C" {
extern "C" {
#[bindgen_pure_virtual]
#[bindgen_original_name("Foo_destructor")]
#[bindgen_special_member("dtor")]
#[link_name = "\u{1}_ZN3FooD1Ev"]
pub fn Foo_Foo_destructor(this: *mut Foo);
}
1 change: 1 addition & 0 deletions tests/expectations/tests/packed-vtable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ impl Default for PackedVtable {
}
extern "C" {
#[bindgen_original_name("PackedVtable_destructor")]
#[bindgen_special_member("dtor")]
#[link_name = "\u{1}_ZN12PackedVtableD1Ev"]
pub fn PackedVtable_PackedVtable_destructor(this: *mut PackedVtable);
}
1 change: 1 addition & 0 deletions tests/expectations/tests/public-dtor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ fn bindgen_test_layout_cv_String() {
}
extern "C" {
#[bindgen_original_name("String_destructor")]
#[bindgen_special_member("dtor")]
#[link_name = "\u{1}_ZN2cv6StringD1Ev"]
pub fn cv_String_String_destructor(this: *mut cv_String);
}
Expand Down
77 changes: 77 additions & 0 deletions tests/expectations/tests/special-members.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#![allow(
dead_code,
non_snake_case,
non_camel_case_types,
non_upper_case_globals
)]

#[repr(C)]
#[derive(Debug, Default)]
pub struct A {
pub _address: u8,
}
#[test]
fn bindgen_test_layout_A() {
assert_eq!(
::std::mem::size_of::<A>(),
1usize,
concat!("Size of: ", stringify!(A))
);
assert_eq!(
::std::mem::align_of::<A>(),
1usize,
concat!("Alignment of ", stringify!(A))
);
}
extern "C" {
#[bindgen_original_name("A")]
#[bindgen_special_member("default_ctor")]
#[link_name = "\u{1}_ZN1AC1Ev"]
pub fn A_A(this: *mut A);
}
extern "C" {
#[bindgen_arg_type_reference(arg1)]
#[bindgen_original_name("A")]
#[bindgen_special_member("copy_ctor")]
#[link_name = "\u{1}_ZN1AC1ERS_"]
pub fn A_A1(this: *mut A, arg1: *mut A);
}
extern "C" {
#[bindgen_arg_type_reference(arg1)]
#[bindgen_original_name("A")]
#[bindgen_special_member("move_ctor")]
#[link_name = "\u{1}_ZN1AC1EOS_"]
pub fn A_A2(this: *mut A, arg1: *mut A);
}
extern "C" {
#[bindgen_original_name("A_destructor")]
#[bindgen_special_member("dtor")]
#[link_name = "\u{1}_ZN1AD1Ev"]
pub fn A_A_destructor(this: *mut A);
}
impl A {
#[inline]
pub unsafe fn new() -> Self {
let mut __bindgen_tmp = ::std::mem::MaybeUninit::uninit();
A_A(__bindgen_tmp.as_mut_ptr());
__bindgen_tmp.assume_init()
}
#[bindgen_arg_type_reference(arg1)]
#[inline]
pub unsafe fn new1(arg1: *mut A) -> Self {
let mut __bindgen_tmp = ::std::mem::MaybeUninit::uninit();
A_A1(__bindgen_tmp.as_mut_ptr(), arg1);
__bindgen_tmp.assume_init()
}
#[bindgen_arg_type_reference(arg1)]
#[inline]
pub unsafe fn new2(arg1: *mut A) -> Self {
let mut __bindgen_tmp = ::std::mem::MaybeUninit::uninit();
A_A2(__bindgen_tmp.as_mut_ptr(), arg1);
__bindgen_tmp.assume_init()
}
#[inline]
pub unsafe fn destruct(&mut self) {
A_A_destructor(self)
}
}
1 change: 1 addition & 0 deletions tests/expectations/tests/union_dtor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ fn bindgen_test_layout_UnionWithDtor() {
}
extern "C" {
#[bindgen_original_name("UnionWithDtor_destructor")]
#[bindgen_special_member("dtor")]
#[link_name = "\u{1}_ZN13UnionWithDtorD1Ev"]
pub fn UnionWithDtor_UnionWithDtor_destructor(this: *mut UnionWithDtor);
}
Expand Down
1 change: 1 addition & 0 deletions tests/expectations/tests/union_dtor_1_0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ fn bindgen_test_layout_UnionWithDtor() {
}
extern "C" {
#[bindgen_original_name("UnionWithDtor_destructor")]
#[bindgen_special_member("dtor")]
#[link_name = "\u{1}_ZN13UnionWithDtorD1Ev"]
pub fn UnionWithDtor_UnionWithDtor_destructor(this: *mut UnionWithDtor);
}
Expand Down
1 change: 1 addition & 0 deletions tests/expectations/tests/virtual_dtor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ impl Default for nsSlots {
}
extern "C" {
#[bindgen_original_name("nsSlots_destructor")]
#[bindgen_special_member("dtor")]
#[link_name = "\u{1}_ZN7nsSlotsD1Ev"]
pub fn nsSlots_nsSlots_destructor(this: *mut nsSlots);
}
7 changes: 7 additions & 0 deletions tests/headers/special-members.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class A {
public:
A();
A(A&);
A(A&&);
~A();
};

0 comments on commit 388d43a

Please sign in to comment.