Skip to content
Closed
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,17 @@
// 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;
48 changes: 48 additions & 0 deletions bindgen/clang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,54 @@ impl Cursor {
unsafe { clang_getCursorExtent(self.x) }
}

/// Returns `true` if the start of `other`'s source range falls 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_start =
clang_getRangeStart(clang_getCursorExtent(other.x));

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;
clang_getFileLocation(
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,
);

parent_file == child_file &&
child_start_off >= parent_start_off &&
child_start_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
16 changes: 15 additions & 1 deletion bindgen/ir/comp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1431,7 +1431,21 @@ 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