Skip to content

codegen: Properly mangle nested anonymous enums with duplicated variants. #346

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 15, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions libbindgen/src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1660,11 +1660,21 @@ impl CodeGenerator for Enum {
match seen_values.entry(variant.val()) {
Entry::Occupied(ref entry) => {
if is_rust_enum {
let existing_variant_name = entry.get();
let variant_name = ctx.rust_mangle(variant.name());
let mangled_name = if is_toplevel || enum_ty.name().is_some() {
variant_name
} else {
let parent_name = parent_canonical_name.as_ref()
.unwrap();

Cow::Owned(
format!("{}_{}", parent_name, variant_name))
};

let existing_variant_name = entry.get();
add_constant(enum_ty,
&name,
&*variant_name,
&*mangled_name,
existing_variant_name,
enum_rust_ty.clone(),
result);
Expand All @@ -1688,8 +1698,6 @@ impl CodeGenerator for Enum {
// If it's an unnamed enum, we also generate a constant so
// it can be properly accessed.
if is_rust_enum && enum_ty.name().is_none() {
// NB: if we want to do this for other kind of nested
// enums we can probably mangle the name.
let mangled_name = if is_toplevel {
variant_name.clone()
} else {
Expand Down
8 changes: 7 additions & 1 deletion libbindgen/src/ir/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,14 @@ impl FunctionSig {
};

let is_method = cursor.kind() == CXCursor_CXXMethod;
let is_constructor = cursor.kind() == CXCursor_Constructor;
if (is_constructor || is_method) &&
cursor.lexical_parent() != cursor.semantic_parent() {
// Only parse constructors once.
return Err(ParseError::Continue);
}

if is_method || cursor.kind() == CXCursor_Constructor {
if is_method || is_constructor {
let is_const = is_method && cursor.method_is_const();
let is_virtual = is_method && cursor.method_is_virtual();
let is_static = is_method && cursor.method_is_static();
Expand Down
47 changes: 47 additions & 0 deletions libbindgen/tests/expectations/tests/anon_enum_trait.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/* automatically generated by rust-bindgen */


#![allow(non_snake_case)]


#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct DataType<_Tp> {
pub _address: u8,
pub _phantom_0: ::std::marker::PhantomData<_Tp>,
}
pub type DataType_value_type<_Tp> = _Tp;
pub type DataType_work_type<_Tp> = DataType_value_type<_Tp>;
pub type DataType_channel_type<_Tp> = DataType_value_type<_Tp>;
pub type DataType_vec_type<_Tp> = DataType_value_type<_Tp>;
pub const DataType_generic_type: DataType__bindgen_ty_1 =
DataType__bindgen_ty_1::generic_type;
pub const DataType_depth: DataType__bindgen_ty_1 =
DataType__bindgen_ty_1::generic_type;
pub const DataType_channels: DataType__bindgen_ty_1 =
DataType__bindgen_ty_1::generic_type;
pub const DataType_fmt: DataType__bindgen_ty_1 =
DataType__bindgen_ty_1::generic_type;
pub const DataType_type_: DataType__bindgen_ty_1 =
DataType__bindgen_ty_1::generic_type;
#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum DataType__bindgen_ty_1 { generic_type = 0, }
#[repr(C)]
#[derive(Debug, Copy)]
pub struct Foo {
pub _address: u8,
}
pub const Foo_Bar: Foo__bindgen_ty_1 = Foo__bindgen_ty_1::Bar;
pub const Foo_Baz: Foo__bindgen_ty_1 = Foo__bindgen_ty_1::Bar;
#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Foo__bindgen_ty_1 { Bar = 0, }
#[test]
fn bindgen_test_layout_Foo() {
assert_eq!(::std::mem::size_of::<Foo>() , 1usize);
assert_eq!(::std::mem::align_of::<Foo>() , 1usize);
}
impl Clone for Foo {
fn clone(&self) -> Self { *self }
}
37 changes: 37 additions & 0 deletions libbindgen/tests/expectations/tests/constructor-tp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/* automatically generated by rust-bindgen */


#![allow(non_snake_case)]


#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Foo<T> {
pub _address: u8,
pub _phantom_0: ::std::marker::PhantomData<T>,
}
#[repr(C)]
#[derive(Debug, Copy)]
pub struct Bar {
pub _address: u8,
}
#[test]
fn bindgen_test_layout_Bar() {
assert_eq!(::std::mem::size_of::<Bar>() , 1usize);
assert_eq!(::std::mem::align_of::<Bar>() , 1usize);
}
extern "C" {
#[link_name = "_ZN3BarC1Ev"]
pub fn Bar_Bar(this: *mut Bar);
}
impl Clone for Bar {
fn clone(&self) -> Self { *self }
}
impl Bar {
#[inline]
pub unsafe fn new() -> Self {
let mut __bindgen_tmp = ::std::mem::uninitialized();
Bar_Bar(&mut __bindgen_tmp);
__bindgen_tmp
}
}
22 changes: 22 additions & 0 deletions libbindgen/tests/headers/anon_enum_trait.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

template<typename _Tp>
class DataType {
public:
typedef _Tp value_type;
typedef value_type work_type;
typedef value_type channel_type;
typedef value_type vec_type;
enum { generic_type = 1,
depth = -1,
channels = 1,
fmt = 0,
type = -1,
};
};

struct Foo {
enum {
Bar = 0,
Baz = 0,
};
};
26 changes: 26 additions & 0 deletions libbindgen/tests/headers/constructor-tp.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@

template<typename T>
class Foo {
public:
Foo();

void doBaz();
};

template<typename T>
inline void
Foo<T>::doBaz() {
}

class Bar {
public:
Bar();
};

template<typename T>
Foo<T>::Foo() {
}

inline
Bar::Bar() {
}