From a68453ce6bea99f7f5df0b2f1bb97ba160e235fa Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Wed, 27 Aug 2025 14:05:50 +0200 Subject: [PATCH 1/2] Get the type's definition in CompInfo::from_ty In https://github.com/llvm/llvm-project/pull/147835, Clang's AST changed so that a TagType's decl will not necessarily refer to the type's definition, but to the exact declaration which produced the type. For example, in typedef struct S T; struct S { int x; }; the 'struct S' type would refer to the incomplete type decl in the typedef, causing CompInfo to fail to see the type's definition. This patch inserts a call to use the definition when available. It fixes the original test case in https://github.com/rust-lang/rust-bindgen/issues/3275 and most of the test failures caused by the Clang change but not all. --- bindgen/ir/comp.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bindgen/ir/comp.rs b/bindgen/ir/comp.rs index 0b50bf3244..f0c4e6f03c 100644 --- a/bindgen/ir/comp.rs +++ b/bindgen/ir/comp.rs @@ -1234,6 +1234,12 @@ impl CompInfo { ); let mut cursor = ty.declaration(); + + // If there is a definition, that's what we want. + if let Some(def) = cursor.definition() { + cursor = def; + } + let mut kind = Self::kind_from_cursor(&cursor); if kind.is_err() { if let Some(location) = location { From 2e7bbcfdbb487100f58d682a39dda3583fbde517 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 27 Aug 2025 15:57:15 +0200 Subject: [PATCH 2/2] clang: Push the fix for #3277 into Type::declaration. Fixes #3264. --- .../expectations/tests/nested-class-field.rs | 22 +++++++++++++++++++ .../tests/headers/nested-class-field.hpp | 7 ++++++ bindgen/clang.rs | 10 ++++----- bindgen/ir/comp.rs | 6 ----- 4 files changed, 34 insertions(+), 11 deletions(-) create mode 100644 bindgen-tests/tests/expectations/tests/nested-class-field.rs create mode 100644 bindgen-tests/tests/headers/nested-class-field.hpp diff --git a/bindgen-tests/tests/expectations/tests/nested-class-field.rs b/bindgen-tests/tests/expectations/tests/nested-class-field.rs new file mode 100644 index 0000000000..91500f4142 --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/nested-class-field.rs @@ -0,0 +1,22 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct A { + pub _address: u8, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of A"][::std::mem::size_of::() - 1usize]; + ["Alignment of A"][::std::mem::align_of::() - 1usize]; +}; +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct A_I { + pub i: ::std::os::raw::c_int, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of A_I"][::std::mem::size_of::() - 4usize]; + ["Alignment of A_I"][::std::mem::align_of::() - 4usize]; + ["Offset of field: A_I::i"][::std::mem::offset_of!(A_I, i) - 0usize]; +}; diff --git a/bindgen-tests/tests/headers/nested-class-field.hpp b/bindgen-tests/tests/headers/nested-class-field.hpp new file mode 100644 index 0000000000..295ebe8129 --- /dev/null +++ b/bindgen-tests/tests/headers/nested-class-field.hpp @@ -0,0 +1,7 @@ +class A { + class I; +}; + +class A::I { + int i; +}; diff --git a/bindgen/clang.rs b/bindgen/clang.rs index e52fed0d4a..1e8326ed82 100644 --- a/bindgen/clang.rs +++ b/bindgen/clang.rs @@ -1211,11 +1211,11 @@ impl Type { /// Get a cursor pointing to this type's declaration. pub(crate) fn declaration(&self) -> Cursor { - unsafe { - Cursor { - x: clang_getTypeDeclaration(self.x), - } - } + let decl = Cursor { + x: unsafe { clang_getTypeDeclaration(self.x) }, + }; + // Prior to clang 22, the declaration pointed to the definition. + decl.definition().unwrap_or(decl) } /// Get the canonical declaration of this type, if it is available. diff --git a/bindgen/ir/comp.rs b/bindgen/ir/comp.rs index f0c4e6f03c..0b50bf3244 100644 --- a/bindgen/ir/comp.rs +++ b/bindgen/ir/comp.rs @@ -1234,12 +1234,6 @@ impl CompInfo { ); let mut cursor = ty.declaration(); - - // If there is a definition, that's what we want. - if let Some(def) = cursor.definition() { - cursor = def; - } - let mut kind = Self::kind_from_cursor(&cursor); if kind.is_err() { if let Some(location) = location {