summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Poveda Ruiz <31802960+pvdrz@users.noreply.github.com>2022-11-10 10:43:02 -0500
committerGitHub <noreply@github.com>2022-11-10 10:43:02 -0500
commitdb4ea32e2d810e765a4c40479e053d0a61a875cf (patch)
treee08d61cdcfb3aa5c7e4fafb0f8dc4eb6261bbfcd
parented3aa90cd4c4e1e59d15942414a6dbc586ac1ed4 (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.rs153
-rw-r--r--bindgen-tests/tests/headers/typedef-pointer-overlap.h30
-rw-r--r--bindgen/ir/ty.rs21
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 => {