Skip to content
Open
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

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// bindgen-flags: --rust-target=1.77

// Regression test for #3295: clang exposes the anonymous struct declared
// inside `__alignof__(...)` of an aligned attribute as a child of the
// surrounding struct. Bindgen used to treat that child as an extra
// anonymous member, doubling the surrounding struct's layout and
// producing failing size assertions in the generated bindings.

typedef struct base_t {
struct {
int aaa;
} __attribute__((aligned(
__alignof__(
struct {int aaa;}
)
)));
} base_t;

typedef struct mixed_t {
struct {
int real_field;
} __attribute__((aligned(
__alignof__(
struct {int phantom;}
)
)));
struct {
int another_real;
};
} mixed_t;
58 changes: 58 additions & 0 deletions bindgen/clang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,64 @@ impl Cursor {
unsafe { clang_getCursorExtent(self.x) }
}

/// Returns `true` if `other`'s source range lies fully within
/// `self`'s source range.
///
/// This is useful for detecting child cursors that clang exposes
/// underneath a parent but whose source location is actually outside the
/// parent's body (e.g. anonymous types declared inside an attribute
/// expression on the parent).
pub(crate) fn extent_contains(&self, other: &Cursor) -> bool {
unsafe {
let parent_range = clang_getCursorExtent(self.x);
let parent_start = clang_getRangeStart(parent_range);
let parent_end = clang_getRangeEnd(parent_range);
let child_range = clang_getCursorExtent(other.x);
let child_start = clang_getRangeStart(child_range);
let child_end = clang_getRangeEnd(child_range);

let mut parent_file = mem::zeroed::<CXFile>();
let mut child_file = mem::zeroed::<CXFile>();
let mut parent_start_off: c_uint = 0;
let mut parent_end_off: c_uint = 0;
let mut child_start_off: c_uint = 0;
let mut child_end_off: c_uint = 0;

clang_getFileLocation(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use the existing helpers for this?

E.g. add fn extent(&self) -> (SourceLocation, SourceLocation) { or so to Cursor?

parent_start,
&mut parent_file,
ptr::null_mut(),
ptr::null_mut(),
&mut parent_start_off,
);
clang_getFileLocation(
parent_end,
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
&mut parent_end_off,
);
clang_getFileLocation(
child_start,
&mut child_file,
ptr::null_mut(),
ptr::null_mut(),
&mut child_start_off,
);
clang_getFileLocation(
child_end,
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
&mut child_end_off,
);

parent_file == child_file &&
child_start_off >= parent_start_off &&
child_end_off <= parent_end_off
}
}

/// Get the raw declaration comment for this referent, if one exists.
pub(crate) fn raw_comment(&self) -> Option<String> {
let s = unsafe {
Expand Down
15 changes: 14 additions & 1 deletion bindgen/ir/comp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1477,7 +1477,20 @@ impl CompInfo {

// A declaration of an union or a struct without name
// could also be an unnamed field, unfortunately.
if cur.is_anonymous() && cur.kind() != CXCursor_EnumDecl
// However, anonymous types declared *outside* the
// parent struct's body — for example an anonymous
// struct that appears inside an `__alignof__`
// expression on the parent's
// `__attribute__((aligned(...)))` — are exposed by
// clang as child cursors of the parent struct, even
// though they are not real members. Skip those by
// checking that the child's source range is inside
// the parent's source range; otherwise we would
// append a phantom field and corrupt the parent's
// layout (#3295).
if cur.is_anonymous() &&
cur.kind() != CXCursor_EnumDecl &&
cursor.extent_contains(&cur)
{
let ty = cur.cur_type();
let public = cur.public_accessible();
Expand Down
Loading