diff --git a/src/clang.rs b/src/clang.rs index 613e08e849..f752aaefe4 100644 --- a/src/clang.rs +++ b/src/clang.rs @@ -1498,6 +1498,13 @@ pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult { &specialized); } } + + if let Some(parent) = c.fallible_semantic_parent() { + println!(""); + print_cursor(depth, + String::from(prefix) + "semantic-parent.", + &parent); + } } fn print_type>(depth: isize, prefix: S, ty: &Type) { diff --git a/src/ir/comp.rs b/src/ir/comp.rs index ce6ec25d14..e8c8b7085c 100644 --- a/src/ir/comp.rs +++ b/src/ir/comp.rs @@ -625,8 +625,19 @@ impl CompInfo { // StructDecl to note incomplete structs that hasn't been // forward-declared before, see: // + // Also, clang seems to scope struct definitions inside + // unions to the whole translation unit. Since those are + // anonymous, let's just assume that if the cursor we've + // found is a definition it's a valid inner type. + // + // Note that doing this could be always ok, but let's just + // keep the union check for now. + // // https://github.com/servo/rust-bindgen/issues/482 - if cur.semantic_parent() != cursor { + let is_inner_struct = cur.semantic_parent() == cursor || + (kind == CompKind::Union && + cur.is_definition()); + if !is_inner_struct { return CXChildVisit_Continue; } diff --git a/src/ir/function.rs b/src/ir/function.rs index 22b9c9b04a..afd2adec56 100644 --- a/src/ir/function.rs +++ b/src/ir/function.rs @@ -91,7 +91,13 @@ fn get_abi(cc: CXCallingConv) -> Option { } /// Get the mangled name for the cursor's referent. -pub fn cursor_mangling(cursor: &clang::Cursor) -> Option { +pub fn cursor_mangling(ctx: &BindgenContext, + cursor: &clang::Cursor) + -> Option { + if !ctx.options().enable_mangling { + return None; + } + // We early return here because libclang may crash in some case // if we pass in a variable inside a partial specialized template. // See servo/rust-bindgen#67, and servo/rust-bindgen#462. @@ -304,7 +310,7 @@ impl ClangSubItemParser for Function { let name = cursor.spelling(); assert!(!name.is_empty(), "Empty function name?"); - let mut mangled_name = cursor_mangling(&cursor); + let mut mangled_name = cursor_mangling(context, &cursor); if mangled_name.as_ref() == Some(&name) { mangled_name = None; } diff --git a/src/ir/var.rs b/src/ir/var.rs index 6cfcdae735..930e07ee03 100644 --- a/src/ir/var.rs +++ b/src/ir/var.rs @@ -238,7 +238,7 @@ impl ClangSubItemParser for Var { .map(VarType::String) }; - let mangling = cursor_mangling(&cursor); + let mangling = cursor_mangling(ctx, &cursor); let var = Var::new(name, mangling, ty, value, is_const); Ok(ParseResult::New(var, Some(cursor))) diff --git a/src/lib.rs b/src/lib.rs index 42363ebdb1..649be323bf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -212,6 +212,18 @@ impl Builder { self } + /// Whether to use the clang-provided name mangling. This is true and + /// probably needed for C++ features. + /// + /// However, some old libclang versions seem to return incorrect results in + /// some cases for non-mangled functions, see [1], so we allow disabling it. + /// + /// [1]: https://github.com/servo/rust-bindgen/issues/528 + pub fn trust_clang_mangling(mut self, doit: bool) -> Self { + self.options.enable_mangling = doit; + self + } + /// Generate a C/C++ file that includes the header and has dummy uses of /// every type defined in the header. pub fn dummy_uses>(mut self, dummy_uses: T) -> Builder { @@ -572,6 +584,15 @@ pub struct BindgenOptions { /// Intead of emitting 'use objc;' to files generated from objective c files, /// generate '#[macro_use] extern crate objc;' pub objc_extern_crate: bool, + + /// Whether to use the clang-provided name mangling. This is true and + /// probably needed for C++ features. + /// + /// However, some old libclang versions seem to return incorrect results in + /// some cases for non-mangled functions, see [1], so we allow disabling it. + /// + /// [1]: https://github.com/servo/rust-bindgen/issues/528 + pub enable_mangling: bool, } /// TODO(emilio): This is sort of a lie (see the error message that results from @@ -626,6 +647,7 @@ impl Default for BindgenOptions { generate_comments: true, whitelist_recursively: true, objc_extern_crate: false, + enable_mangling: true, } } } diff --git a/src/options.rs b/src/options.rs index e54ee0124e..a62aa73d28 100644 --- a/src/options.rs +++ b/src/options.rs @@ -60,6 +60,9 @@ pub fn builder_from_flags Arg::with_name("objc-extern-crate") .long("objc-extern-crate") .help("Use extern crate instead of use for objc"), + Arg::with_name("distrust-clang-mangling") + .long("distrust-clang-mangling") + .help("Do not trust the libclang-provided mangling"), Arg::with_name("builtins") .long("builtins") .help("Output bindings for builtin definitions, e.g. \ diff --git a/tests/expectations/tests/anon_struct_in_union.rs b/tests/expectations/tests/anon_struct_in_union.rs new file mode 100644 index 0000000000..97a342cfff --- /dev/null +++ b/tests/expectations/tests/anon_struct_in_union.rs @@ -0,0 +1,92 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +pub struct __BindgenUnionField(::std::marker::PhantomData); +impl __BindgenUnionField { + #[inline] + pub fn new() -> Self { __BindgenUnionField(::std::marker::PhantomData) } + #[inline] + pub unsafe fn as_ref(&self) -> &T { ::std::mem::transmute(self) } + #[inline] + pub unsafe fn as_mut(&mut self) -> &mut T { ::std::mem::transmute(self) } +} +impl ::std::default::Default for __BindgenUnionField { + #[inline] + fn default() -> Self { Self::new() } +} +impl ::std::clone::Clone for __BindgenUnionField { + #[inline] + fn clone(&self) -> Self { Self::new() } +} +impl ::std::marker::Copy for __BindgenUnionField { } +impl ::std::fmt::Debug for __BindgenUnionField { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fmt.write_str("__BindgenUnionField") + } +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct s { + pub u: s__bindgen_ty_1, +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct s__bindgen_ty_1 { + pub field: __BindgenUnionField, + pub bindgen_union_field: u32, +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct s__bindgen_ty_1_inner { + pub b: ::std::os::raw::c_int, +} +#[test] +fn bindgen_test_layout_s__bindgen_ty_1_inner() { + assert_eq!(::std::mem::size_of::() , 4usize , + concat ! ( "Size of: " , stringify ! ( s__bindgen_ty_1_inner ) + )); + assert_eq! (::std::mem::align_of::() , 4usize , + concat ! ( + "Alignment of " , stringify ! ( s__bindgen_ty_1_inner ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const s__bindgen_ty_1_inner ) ) . b as * const + _ as usize } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( s__bindgen_ty_1_inner ) + , "::" , stringify ! ( b ) )); +} +impl Clone for s__bindgen_ty_1_inner { + fn clone(&self) -> Self { *self } +} +#[test] +fn bindgen_test_layout_s__bindgen_ty_1() { + assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( + "Size of: " , stringify ! ( s__bindgen_ty_1 ) )); + assert_eq! (::std::mem::align_of::() , 4usize , concat ! + ( "Alignment of " , stringify ! ( s__bindgen_ty_1 ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const s__bindgen_ty_1 ) ) . field as * const _ + as usize } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( s__bindgen_ty_1 ) , + "::" , stringify ! ( field ) )); +} +impl Clone for s__bindgen_ty_1 { + fn clone(&self) -> Self { *self } +} +#[test] +fn bindgen_test_layout_s() { + assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( + "Size of: " , stringify ! ( s ) )); + assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( + "Alignment of " , stringify ! ( s ) )); + assert_eq! (unsafe { & ( * ( 0 as * const s ) ) . u as * const _ as usize + } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( s ) , "::" , stringify + ! ( u ) )); +} +impl Clone for s { + fn clone(&self) -> Self { *self } +} diff --git a/tests/headers/anon_struct_in_union.h b/tests/headers/anon_struct_in_union.h new file mode 100644 index 0000000000..880a8b5453 --- /dev/null +++ b/tests/headers/anon_struct_in_union.h @@ -0,0 +1,7 @@ +struct s { + union { + struct inner { + int b; + } field; + } u; +};