diff options
author | Christian Poveda Ruiz <31802960+pvdrz@users.noreply.github.com> | 2022-11-10 10:43:02 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-11-10 10:43:02 -0500 |
commit | db4ea32e2d810e765a4c40479e053d0a61a875cf (patch) | |
tree | e08d61cdcfb3aa5c7e4fafb0f8dc4eb6261bbfcd | |
parent | ed3aa90cd4c4e1e59d15942414a6dbc586ac1ed4 (diff) |
Handle the `const struct *` and `struct *` patterns (#2304)
Given that C keeps a different namespace for `struct`/`enum`/`union` and `typedef` aliases. The
following patterns
```c
typedef const struct foo {
void *inner;
} *foo;
typedef struct bar {
void *inner;
} *bar;
```
are valid C code and produces both a `struct` and a pointer called `foo`
and `bar` in different namespaces. Given that Rust does not make this
distinction, we add the `_ptr` prefix to the pointer type aliases to
avoid any name collisions.
-rw-r--r-- | bindgen-tests/tests/expectations/tests/typedef-pointer-overlap.rs | 153 | ||||
-rw-r--r-- | bindgen-tests/tests/headers/typedef-pointer-overlap.h | 30 | ||||
-rw-r--r-- | bindgen/ir/ty.rs | 21 |
3 files changed, 201 insertions, 3 deletions
diff --git a/bindgen-tests/tests/expectations/tests/typedef-pointer-overlap.rs b/bindgen-tests/tests/expectations/tests/typedef-pointer-overlap.rs new file mode 100644 index 00000000..2d5c5aae --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/typedef-pointer-overlap.rs @@ -0,0 +1,153 @@ +#![allow( + dead_code, + non_snake_case, + non_camel_case_types, + non_upper_case_globals +)] + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct foo { + pub inner: ::std::os::raw::c_char, +} +#[test] +fn bindgen_test_layout_foo() { + const UNINIT: ::std::mem::MaybeUninit<foo> = + ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::<foo>(), + 1usize, + concat!("Size of: ", stringify!(foo)) + ); + assert_eq!( + ::std::mem::align_of::<foo>(), + 1usize, + concat!("Alignment of ", stringify!(foo)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).inner) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(foo), + "::", + stringify!(inner) + ) + ); +} +pub type foo_ptr = *const foo; +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct bar { + pub inner: ::std::os::raw::c_char, +} +#[test] +fn bindgen_test_layout_bar() { + const UNINIT: ::std::mem::MaybeUninit<bar> = + ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::<bar>(), + 1usize, + concat!("Size of: ", stringify!(bar)) + ); + assert_eq!( + ::std::mem::align_of::<bar>(), + 1usize, + concat!("Alignment of ", stringify!(bar)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).inner) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(bar), + "::", + stringify!(inner) + ) + ); +} +pub type bar_ptr = *mut bar; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct baz { + _unused: [u8; 0], +} +pub type baz_ptr = *mut baz; +#[repr(C)] +#[derive(Copy, Clone)] +pub union cat { + pub standard_issue: ::std::os::raw::c_int, +} +#[test] +fn bindgen_test_layout_cat() { + const UNINIT: ::std::mem::MaybeUninit<cat> = + ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::<cat>(), + 4usize, + concat!("Size of: ", stringify!(cat)) + ); + assert_eq!( + ::std::mem::align_of::<cat>(), + 4usize, + concat!("Alignment of ", stringify!(cat)) + ); + assert_eq!( + unsafe { + ::std::ptr::addr_of!((*ptr).standard_issue) as usize - ptr as usize + }, + 0usize, + concat!( + "Offset of field: ", + stringify!(cat), + "::", + stringify!(standard_issue) + ) + ); +} +impl Default for cat { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::<Self>::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +pub type cat_ptr = *mut cat; +pub const mad_scientist: mad = 0; +pub type mad = ::std::os::raw::c_uint; +pub type mad_ptr = *mut mad; +extern "C" { + pub fn takes_foo_ptr(arg1: foo_ptr); +} +extern "C" { + pub fn takes_foo_struct(arg1: foo); +} +extern "C" { + pub fn takes_bar_ptr(arg1: bar_ptr); +} +extern "C" { + pub fn takes_bar_struct(arg1: bar); +} +extern "C" { + pub fn takes_baz_ptr(arg1: baz_ptr); +} +extern "C" { + pub fn takes_baz_struct(arg1: baz); +} +extern "C" { + pub fn takes_cat_ptr(arg1: cat_ptr); +} +extern "C" { + pub fn takes_cat_union(arg1: cat); +} +extern "C" { + pub fn takes_mad_ptr(arg1: mad_ptr); +} +extern "C" { + pub fn takes_mad_enum(arg1: mad); +} diff --git a/bindgen-tests/tests/headers/typedef-pointer-overlap.h b/bindgen-tests/tests/headers/typedef-pointer-overlap.h new file mode 100644 index 00000000..8c556c9b --- /dev/null +++ b/bindgen-tests/tests/headers/typedef-pointer-overlap.h @@ -0,0 +1,30 @@ +typedef const struct foo { + char inner; +} *foo; + +typedef struct bar { + char inner; +} *bar; + +typedef struct baz *baz; + +typedef union cat { + int standard_issue; +} *cat; + +typedef enum mad { scientist } *mad; + +void takes_foo_ptr(foo); +void takes_foo_struct(struct foo); + +void takes_bar_ptr(bar); +void takes_bar_struct(struct bar); + +void takes_baz_ptr(baz); +void takes_baz_struct(struct baz); + +void takes_cat_ptr(cat); +void takes_cat_union(union cat); + +void takes_mad_ptr(mad); +void takes_mad_enum(enum mad); diff --git a/bindgen/ir/ty.rs b/bindgen/ir/ty.rs index c9403f66..fd6108f7 100644 --- a/bindgen/ir/ty.rs +++ b/bindgen/ir/ty.rs @@ -1094,9 +1094,9 @@ impl Type { } CXType_Typedef => { let inner = cursor.typedef_type().expect("Not valid Type?"); - let inner = + let inner_id = Item::from_ty_or_ref(inner, location, None, ctx); - if inner == potential_id { + if inner_id == potential_id { warn!( "Generating oqaque type instead of self-referential \ typedef"); @@ -1104,7 +1104,22 @@ impl Type { // within the clang parsing. TypeKind::Opaque } else { - TypeKind::Alias(inner) + // Check if this type definition is an alias to a pointer of a `struct` / + // `union` / `enum` with the same name and add the `_ptr` suffix to it to + // avoid name collisions. + if let Some(ref mut name) = name { + if inner.kind() == CXType_Pointer && + !ctx.options().c_naming + { + let pointee = inner.pointee_type().unwrap(); + if pointee.kind() == CXType_Elaborated && + pointee.declaration().spelling() == *name + { + *name += "_ptr"; + } + } + } + TypeKind::Alias(inner_id) } } CXType_Enum => { |