-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[Clang] Handle structs with inner structs and no fields #89126
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
36ddb58
fbb22e6
4c4046f
350550b
d3eda51
dad1c32
1613ce6
f9b3bf3
1b79233
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 4 | ||
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -Wno-missing-declarations -emit-llvm -o - %s | FileCheck %s | ||
|
||
struct foo { | ||
struct bar { | ||
int count; | ||
int array[] __attribute__((counted_by(count))); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ideally, we should be able to compute the size here; would need to change the way we compute the "outer" type. Can leave that for a followup, I guess. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can, if handling There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The only reason foo is relevant in the first place is that getOuterLexicalRecordContext() skips over bar. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see what you mean. I'd like to leave it for a followup, since this change is meant to fix an ICE. |
||
}; | ||
}; | ||
|
||
void init(void * __attribute__((pass_dynamic_object_size(0)))); | ||
|
||
// CHECK-LABEL: define dso_local void @test1( | ||
// CHECK-SAME: ptr noundef [[P:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { | ||
// CHECK-NEXT: entry: | ||
// CHECK-NEXT: [[ARRAY:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 4 | ||
// CHECK-NEXT: tail call void @init(ptr noundef nonnull [[ARRAY]], i64 noundef -1) #[[ATTR2:[0-9]+]] | ||
// CHECK-NEXT: ret void | ||
// | ||
void test1(struct bar *p) { | ||
init(p->array); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 4 | ||
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -Wall -emit-llvm -o - %s | FileCheck %s | ||
|
||
struct foo { | ||
struct bar { | ||
int array[]; | ||
bar(); | ||
}; | ||
}; | ||
|
||
void init(void * __attribute__((pass_dynamic_object_size(0)))); | ||
|
||
// CHECK-LABEL: define dso_local void @_ZN3foo3barC1Ev( | ||
// CHECK-SAME: ptr noundef nonnull align 4 dereferenceable(1) [[THIS:%.*]]) unnamed_addr #[[ATTR0:[0-9]+]] align 2 { | ||
// CHECK-NEXT: entry: | ||
// CHECK-NEXT: tail call void @_Z4initPvU25pass_dynamic_object_size0(ptr noundef nonnull [[THIS]], i64 noundef -1) #[[ATTR2:[0-9]+]] | ||
// CHECK-NEXT: ret void | ||
// | ||
foo::bar::bar() { | ||
init(array); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FieldNo and Layout are referring to fields of "RD"; the "Field" found in the recursive visit is a member of Record (or some subobject of Record). So the code is doing math on completely unrelated offsets. Checking getFieldCount is just masking the issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe instead of looking for RecordDecls, this code should be looking for fields where the type of the field is an anonymous struct/union.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's not the issue. What's happening is when an inner struct is declared/defined, we recurse within it to try to find the
Field
offset. If we do find it, thenOffset
has the offset value withinRecord
. At this point, what we need is the offset up to theRecordDecl
, but since those may or may not have a field number associated with them, we use the lastFieldNo
to get that offset.A bit clearer:
This has obvious issues with virtual classes and the like, which is why C++ doesn't officially support FAMs (I believe it's an extension).
To be fair, I had the same question you had. I should document this better.
We want to look into all inner structs to find a FAM that may be lurking deep down within the bowels of the struct, which may involve non-anonymous structs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did several tests, and it looks like if there's an inner struct that's not accessible, that doesn't affect the offsets of fields outside of that inner struct.
@efriedma-quic Do you have any thoughts?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the only thing that's relevant to offsets in a struct is the fields. A struct definition inside another struct declaration has exactly the same semantics as a struct definition anywhere else (unless it's an anonymous struct/union).
Maybe also try the following testcase.