Repository navigation
fix(folding): correct unique object rep checks [] #326
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
base: main
Are you sure you want to change the base?
Changes from all commits
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 |
|---|---|---|
| @@ -1,5 +1,35 @@ | ||
| Version 7.1 | ||
|
|
||
| 10/16/26 | ||
| __has_unique_object_representations fixes | ||
|
|
||
| A base class that declares no nonstatic data members of its own but inherits | ||
| some (and is therefore not empty) was treated as an empty base class. Its | ||
| size was then counted as tail padding, so the trait was incorrectly FALSE for | ||
| classes derived from it. For example, with --g++: | ||
|
|
||
| struct A { char i; }; | ||
| struct B : A {}; | ||
| struct C : B {}; | ||
| static_assert(__has_unique_object_representations(C)); // Previously | ||
| // failed. | ||
|
|
||
| This is now fixed. In addition, the following version-dependent behaviors | ||
| of g++ and Clang are now emulated: | ||
|
|
||
| - An unnamed bit-field of nonzero width is treated as padding (making the | ||
|
Contributor
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. What should the behavior for standard-mode be in this case? |
||
| result FALSE) in g++ 10.5, 11.4, 12.3, 13.1 and later, and in Clang 17 | ||
| and later. For example: | ||
|
|
||
| struct S { char a; char : 8; char b; }; | ||
| // __has_unique_object_representations(S) is now FALSE in those modes. | ||
|
|
||
| - Volatile-qualified non-class types (e.g., "volatile int") are treated as | ||
| not having unique object representations only in g++ modes before | ||
| version 10 (previously this was done for all g++ versions, including | ||
| Clang modes). | ||
|
|
||
|
|
||
| 10/16/26 [GH #229] | ||
| Improper handling of "if constexpr" substatements | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8939,6 +8939,26 @@ with cssp are trivial. | |
| } /* all_copy_constructors_trivial */ | ||
|
|
||
|
|
||
| static a_boolean unnamed_bit_field_is_padding(void) | ||
| /* | ||
| Return TRUE if an unnamed bit-field of non-zero width is considered padding | ||
| by type_has_unique_object_representations. That is the case for Clang 17 | ||
| and later and for g++ 13.1 and later (the change was also backported to | ||
| g++ 10.5, 11.4, and 12.3). | ||
| */ | ||
| { | ||
| a_boolean result = FALSE; | ||
|
|
||
| if (clang_mode) { | ||
| result = clang_version >= 170000; | ||
| } else if (gpp_mode) { | ||
| result = gnu_version >= 120300 || | ||
| (gnu_version >= 110400 && gnu_version < 120000) || | ||
| (gnu_version >= 100500 && gnu_version < 110000); | ||
| } /* if */ | ||
| return result; | ||
| } /* unnamed_bit_field_is_padding */ | ||
|
|
||
| static a_boolean type_has_unique_object_representations( | ||
| a_type_ptr type, | ||
| a_targ_size_t *after_base_members, | ||
|
|
@@ -8999,8 +9019,7 @@ architectures for which these assumptions are not valid. | |
| if (bcp->offset != end_of_last_subobject) { | ||
| /* There's padding between base class subobjects. */ | ||
| result = FALSE; | ||
| } else if (bcp->type->variant.class_struct_union.field_list == | ||
| NULL) { | ||
| } else if (is_empty_class_type(bcp->type)) { | ||
| /* An empty base class: treat it as having size 0 and do not | ||
| check type_has_unique_object_representation, since an empty | ||
| class will consist of nothing but padding. If it was not | ||
|
|
@@ -9035,6 +9054,12 @@ architectures for which these assumptions are not valid. | |
| same size or (for g++, not clang) if a bit-field is shorter | ||
| than the size of the union. */ | ||
| result = FALSE; | ||
| } else if (field->is_bit_field && field->bit_size != 0 && | ||
| unnamed_bit_field_is_padding() && | ||
| field->source_corresp.assoc_info == | ||
| (char *)get_unnamed_field_symbol()) { | ||
| /* An unnamed bit-field of non-zero width is padding. */ | ||
| result = FALSE; | ||
|
Contributor
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. Does that need to be restricted to non-union class types? |
||
| } else if (field->offset != end_of_last_subobject || | ||
| field->offset_bit_remainder != bit_offset_of_end) { | ||
| /* There's padding between nonstatic data members. */ | ||
|
|
@@ -9078,9 +9103,10 @@ architectures for which these assumptions are not valid. | |
| } /* if */ | ||
| } /* if */ | ||
| } /* if */ | ||
| } else if (gpp_mode && is_volatile_qualified_type(orig_type)) { | ||
| /* g++ treats volatile-qualified types as not having unique object | ||
| representations. */ | ||
| } else if (gpp_mode && !clang_mode && gnu_version < 100000 && | ||
| is_volatile_qualified_type(orig_type)) { | ||
| /* g++ before version 10 treats volatile-qualified non-class types as | ||
| not having unique object representations. */ | ||
| result = FALSE; | ||
| } else { | ||
| /* A non-class type. */ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,16 +1 @@ | ||
| fe_only -DTEST_NUMBER=1 --gnu_version=999999 -tused -e 200 --no_wrap --no_wrap_diagnostics --c++11 Test_name.c | ||
| "Test_name.c", line 10: error: static assertion failed with "" | ||
| static_assert (__has_unique_object_representations (U) == false, ""); | ||
| ^ | ||
| "Test_name.c", line 10: note: the final comparison was 1 == 0 | ||
| static_assert (__has_unique_object_representations (U) == false, ""); | ||
| ^ | ||
|
|
||
| "Test_name.c", line 11: error: static assertion failed with "" | ||
| static_assert (__has_unique_object_representations (V) == false, ""); | ||
| ^ | ||
| "Test_name.c", line 11: note: the final comparison was 1 == 0 | ||
| static_assert (__has_unique_object_representations (V) == false, ""); | ||
| ^ | ||
|
|
||
| 2 errors detected in the compilation of "Test_name.c". |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| fe_only -DTEST_NUMBER=1 --c++17 --g++ --gnu_version=150100 Test_name.c |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| fe_only -DTEST_NUMBER=2 --c++17 --clang --clang_version=190000 Test_name.c |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| //remark:has_unique_object_representations with a base that has no direct fields | ||
| //type:fp | ||
| //options_all:--c++17 | ||
| //options:--g++ --gnu_version=150100:--clang --clang_version=190000 | ||
|
Contributor
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 test case should also test standard mode (and ideally, also MSVC modes). Also need to have test coverage for the other code changes (unnamed bit-field, volatile qualifiers). Should also test each version condition from the source code. |
||
|
|
||
| // B declares no fields but is not empty (it inherits A::i), so it must not | ||
| // be skipped as an empty base when checking C. | ||
| struct A { char i; }; | ||
| struct B : A {}; | ||
| struct C : B {}; | ||
| struct D : C {}; | ||
| struct E {}; | ||
| struct F : E, B {}; // Real empty base is still skipped. | ||
| struct G : B { char j; }; | ||
| struct P { int i; char c; }; // Tail padding. | ||
| struct Q : P {}; | ||
|
|
||
| static_assert(__has_unique_object_representations(B), "B"); | ||
| static_assert(__has_unique_object_representations(C), "C"); | ||
| static_assert(__has_unique_object_representations(D), "D"); | ||
| static_assert(__has_unique_object_representations(F), "F"); | ||
| static_assert(__has_unique_object_representations(G), "G"); | ||
| static_assert(!__has_unique_object_representations(P), "P"); | ||
| static_assert(!__has_unique_object_representations(Q), "Q"); | ||
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.
The issue is not actually gcc specific, but also applies to default/standard mode, so should just have an example with
--c++11.