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
41 changes: 41 additions & 0 deletions src/Changes
Original file line number Diff line number Diff line change
@@ -1,5 +1,46 @@
Version 7.1

10/16/26 [GH #327]
__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 --c++11:

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:

- An unnamed bit-field of nonzero width is now treated as padding (making
the result FALSE), as the standard requires. For example:

struct S { char a; char : 8; char b; };
// __has_unique_object_representations(S) is now FALSE.

The previous behavior (TRUE) is retained in g++ modes before 13.1
(except 10.5, 11.4, and 12.3) and in Clang modes before 17.

- In a union, an unnamed bit-field overlaps the other members, so the
rule above does not apply; as before, a bit-field narrower than the
union is treated as padding, except in Clang modes. Microsoft mode now
also does not treat it as padding, matching MSVC. For example:

union U { int x : 3; };
// __has_unique_object_representations(U) is now TRUE with
// --microsoft.

- 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). In other modes the result is the same as for the
unqualified type, as the standard requires.


10/15/26 [GH #309]
Position of (lowered) cleanups at the end of a function body

Expand Down
46 changes: 38 additions & 8 deletions src/folding.c
Original file line number Diff line number Diff line change
Expand Up @@ -8939,6 +8939,27 @@ 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 standard behavior;
it is not done by Clang before version 17 or by g++ before 13.1 (except for
the backports to g++ 10.5, 11.4, and 12.3).
*/
{
a_boolean result = TRUE;

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,
Expand Down Expand Up @@ -8999,8 +9020,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
Expand Down Expand Up @@ -9029,11 +9049,20 @@ architectures for which these assumptions are not valid.
a_type_ptr field_type = skip_typerefs(field->type);
if (type->kind == (a_type_kind)tk_union &&
((prev_field != NULL && field_type->size != prev_field_size) ||
(field->is_bit_field && !clang_mode &&
(field->is_bit_field && !clang_mode && !microsoft_mode &&
field->bit_size < type->size * targ_char_bit))) {
/* There will be padding in a union if not all fields are the
same size or (for g++, not clang) if a bit-field is shorter
than the size of the union. */
same size or (except for Clang and Microsoft) if a bit-field
is shorter than the size of the union. */
result = FALSE;
} else if (type->kind != tk_union &&
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. (In a
union, an unnamed bit-field overlaps the other members, so
it is handled by the size test above instead.) */
result = FALSE;

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.

Does that need to be restricted to non-union class types?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Yes, it should. In a union, an unnamed bit-field overlaps the other members, so it shouldn't be treated as padding on its own. Instead, any bit-field narrower than the union is treated as padding, except in Clang and Microsoft modes (which ignore that case). This is now implemented and tests have been added.

} else if (field->offset != end_of_last_subobject ||
field->offset_bit_remainder != bit_offset_of_end) {
Expand Down Expand Up @@ -9078,9 +9107,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_version_is(< 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. */
Expand Down
1 change: 0 additions & 1 deletion tests/expectations/edg_x86_64/imported.log
Original file line number Diff line number Diff line change
Expand Up @@ -6872,7 +6872,6 @@ gnu/cpp/cpp1z/fold1/test.mft.cpp:fn:-DTEST_NUMBER=1 --c++17:FAIL:
gnu/cpp/cpp1z/fold5.sft.cpp:fn:-DTEST_NUMBER=1 --c++11:FAIL:
gnu/cpp/cpp1z/fold6.sft.cpp:fn:-DTEST_NUMBER=1 --c++17:FAIL:
gnu/cpp/cpp1z/has-unique-obj-representations1.sft.cpp:fp:-DTEST_NUMBER=1 --c++11:FAIL:
gnu/cpp/cpp1z/has-unique-obj-representations3.sft.cpp:fp:-DTEST_NUMBER=1 --c++11:FAIL:
gnu/cpp/cpp1z/inh-ctor1.sft.cpp:fn:-DTEST_NUMBER=1 --c++11:FAIL:
gnu/cpp/cpp1z/inh-ctor33.sft.cpp:lp:-DTEST_NUMBER=1 --c++11:FAIL:
gnu/cpp/cpp1z/inh-ctor38.sft.cpp:rp:-DTEST_NUMBER=1 --c++11:FAIL:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -375,38 +375,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
static_assert(!__is_trivially_destructible(AnIncompleteType[1])); // expected-error {{incomplete type}}
^

"Test_name.c", line 3482: error: static assertion failed with "integrals are"
static_assert(__has_unique_object_representations(volatile int), "integrals are");
^

"Test_name.c", line 3483: error: static assertion failed with "integrals are"
static_assert(__has_unique_object_representations(const volatile int), "integrals are");
^

"Test_name.c", line 3502: error: static assertion failed with "even function pointers"
static_assert(__has_unique_object_representations(volatile FP), "even function pointers");
^

"Test_name.c", line 3503: error: static assertion failed with "even function pointers"
static_assert(__has_unique_object_representations(const volatile FP), "even function pointers");
^

"Test_name.c", line 3507: error: static assertion failed with "and pointer to members"
static_assert(__has_unique_object_representations(volatile PMF), "and pointer to members");
^

"Test_name.c", line 3508: error: static assertion failed with "and pointer to members"
static_assert(__has_unique_object_representations(const volatile PMF), "and pointer to members");
^

"Test_name.c", line 3512: error: static assertion failed with "and pointer to members"
static_assert(__has_unique_object_representations(volatile PMD), "and pointer to members");
^

"Test_name.c", line 3513: error: static assertion failed with "and pointer to members"
static_assert(__has_unique_object_representations(const volatile PMD), "and pointer to members");
^

"Test_name.c", line 3544: error: an incomplete class type is not allowed
static_assert(!__has_unique_object_representations(AnIncompleteType));
^
Expand All @@ -431,14 +399,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
char d : 1;
^

"Test_name.c", line 3777: error: static assertion failed with "Bitfield padding"
static_assert(!__has_unique_object_representations(UnnamedBitfield), "Bitfield padding");
^

"Test_name.c", line 3778: error: static assertion failed with "Bitfield padding"
static_assert(!__has_unique_object_representations(UnnamedBitfieldPacked), "Bitfield padding");
^

"Test_name.c", line 3790: warning: declared size for bit field is larger than the size of the bit field type; truncated to 8 bits
bool b : 16;
^
Expand Down Expand Up @@ -695,5 +655,5 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
#error Programming model currently unsupported; please add a new entry.
^

124 errors and 1 catastrophic error detected in the compilation of "Test_name.c".
114 errors and 1 catastrophic error detected in the compilation of "Test_name.c".
Compilation terminated.
Original file line number Diff line number Diff line change
Expand Up @@ -379,38 +379,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
static_assert(!__is_trivially_destructible(AnIncompleteType[1])); // expected-error {{incomplete type}}
^

"Test_name.c", line 3482: error: static assertion failed with "integrals are"
static_assert(__has_unique_object_representations(volatile int), "integrals are");
^

"Test_name.c", line 3483: error: static assertion failed with "integrals are"
static_assert(__has_unique_object_representations(const volatile int), "integrals are");
^

"Test_name.c", line 3502: error: static assertion failed with "even function pointers"
static_assert(__has_unique_object_representations(volatile FP), "even function pointers");
^

"Test_name.c", line 3503: error: static assertion failed with "even function pointers"
static_assert(__has_unique_object_representations(const volatile FP), "even function pointers");
^

"Test_name.c", line 3507: error: static assertion failed with "and pointer to members"
static_assert(__has_unique_object_representations(volatile PMF), "and pointer to members");
^

"Test_name.c", line 3508: error: static assertion failed with "and pointer to members"
static_assert(__has_unique_object_representations(const volatile PMF), "and pointer to members");
^

"Test_name.c", line 3512: error: static assertion failed with "and pointer to members"
static_assert(__has_unique_object_representations(volatile PMD), "and pointer to members");
^

"Test_name.c", line 3513: error: static assertion failed with "and pointer to members"
static_assert(__has_unique_object_representations(const volatile PMD), "and pointer to members");
^

"Test_name.c", line 3544: error: an incomplete class type is not allowed
static_assert(!__has_unique_object_representations(AnIncompleteType));
^
Expand All @@ -435,14 +403,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
char d : 1;
^

"Test_name.c", line 3777: error: static assertion failed with "Bitfield padding"
static_assert(!__has_unique_object_representations(UnnamedBitfield), "Bitfield padding");
^

"Test_name.c", line 3778: error: static assertion failed with "Bitfield padding"
static_assert(!__has_unique_object_representations(UnnamedBitfieldPacked), "Bitfield padding");
^

"Test_name.c", line 3790: warning: declared size for bit field is larger than the size of the bit field type; truncated to 8 bits
bool b : 16;
^
Expand Down Expand Up @@ -695,5 +655,5 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
#error Programming model currently unsupported; please add a new entry.
^

124 errors and 1 catastrophic error detected in the compilation of "Test_name.c".
114 errors and 1 catastrophic error detected in the compilation of "Test_name.c".
Compilation terminated.
Original file line number Diff line number Diff line change
Expand Up @@ -363,38 +363,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
static_assert(!__is_trivially_destructible(AnIncompleteType[1])); // expected-error {{incomplete type}}
^

"Test_name.c", line 3482: error: static assertion failed with "integrals are"
static_assert(__has_unique_object_representations(volatile int), "integrals are");
^

"Test_name.c", line 3483: error: static assertion failed with "integrals are"
static_assert(__has_unique_object_representations(const volatile int), "integrals are");
^

"Test_name.c", line 3502: error: static assertion failed with "even function pointers"
static_assert(__has_unique_object_representations(volatile FP), "even function pointers");
^

"Test_name.c", line 3503: error: static assertion failed with "even function pointers"
static_assert(__has_unique_object_representations(const volatile FP), "even function pointers");
^

"Test_name.c", line 3507: error: static assertion failed with "and pointer to members"
static_assert(__has_unique_object_representations(volatile PMF), "and pointer to members");
^

"Test_name.c", line 3508: error: static assertion failed with "and pointer to members"
static_assert(__has_unique_object_representations(const volatile PMF), "and pointer to members");
^

"Test_name.c", line 3512: error: static assertion failed with "and pointer to members"
static_assert(__has_unique_object_representations(volatile PMD), "and pointer to members");
^

"Test_name.c", line 3513: error: static assertion failed with "and pointer to members"
static_assert(__has_unique_object_representations(const volatile PMD), "and pointer to members");
^

"Test_name.c", line 3544: error: an incomplete class type is not allowed
static_assert(!__has_unique_object_representations(AnIncompleteType));
^
Expand All @@ -419,14 +387,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
char d : 1;
^

"Test_name.c", line 3777: error: static assertion failed with "Bitfield padding"
static_assert(!__has_unique_object_representations(UnnamedBitfield), "Bitfield padding");
^

"Test_name.c", line 3778: error: static assertion failed with "Bitfield padding"
static_assert(!__has_unique_object_representations(UnnamedBitfieldPacked), "Bitfield padding");
^

"Test_name.c", line 3790: warning: declared size for bit field is larger than the size of the bit field type; truncated to 8 bits
bool b : 16;
^
Expand Down Expand Up @@ -635,5 +595,5 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
#error Programming model currently unsupported; please add a new entry.
^

124 errors and 1 catastrophic error detected in the compilation of "Test_name.c".
114 errors and 1 catastrophic error detected in the compilation of "Test_name.c".
Compilation terminated.
Original file line number Diff line number Diff line change
Expand Up @@ -359,38 +359,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
static_assert(!__is_trivially_destructible(AnIncompleteType[1])); // expected-error {{incomplete type}}
^

"Test_name.c", line 3482: error: static assertion failed with "integrals are"
static_assert(__has_unique_object_representations(volatile int), "integrals are");
^

"Test_name.c", line 3483: error: static assertion failed with "integrals are"
static_assert(__has_unique_object_representations(const volatile int), "integrals are");
^

"Test_name.c", line 3502: error: static assertion failed with "even function pointers"
static_assert(__has_unique_object_representations(volatile FP), "even function pointers");
^

"Test_name.c", line 3503: error: static assertion failed with "even function pointers"
static_assert(__has_unique_object_representations(const volatile FP), "even function pointers");
^

"Test_name.c", line 3507: error: static assertion failed with "and pointer to members"
static_assert(__has_unique_object_representations(volatile PMF), "and pointer to members");
^

"Test_name.c", line 3508: error: static assertion failed with "and pointer to members"
static_assert(__has_unique_object_representations(const volatile PMF), "and pointer to members");
^

"Test_name.c", line 3512: error: static assertion failed with "and pointer to members"
static_assert(__has_unique_object_representations(volatile PMD), "and pointer to members");
^

"Test_name.c", line 3513: error: static assertion failed with "and pointer to members"
static_assert(__has_unique_object_representations(const volatile PMD), "and pointer to members");
^

"Test_name.c", line 3544: error: an incomplete class type is not allowed
static_assert(!__has_unique_object_representations(AnIncompleteType));
^
Expand All @@ -415,14 +383,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
char d : 1;
^

"Test_name.c", line 3777: error: static assertion failed with "Bitfield padding"
static_assert(!__has_unique_object_representations(UnnamedBitfield), "Bitfield padding");
^

"Test_name.c", line 3778: error: static assertion failed with "Bitfield padding"
static_assert(!__has_unique_object_representations(UnnamedBitfieldPacked), "Bitfield padding");
^

"Test_name.c", line 3790: warning: declared size for bit field is larger than the size of the bit field type; truncated to 8 bits
bool b : 16;
^
Expand Down Expand Up @@ -635,5 +595,5 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
#error Programming model currently unsupported; please add a new entry.
^

124 errors and 1 catastrophic error detected in the compilation of "Test_name.c".
114 errors and 1 catastrophic error detected in the compilation of "Test_name.c".
Compilation terminated.
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++11 -DSTD_MODE Test_name.c
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fe_only -DTEST_NUMBER=10 --c++11 --microsoft Test_name.c
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fe_only -DTEST_NUMBER=2 --c++11 --g++ --gnu_version=90400 -DOLD_PAD Test_name.c
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fe_only -DTEST_NUMBER=3 --c++11 --g++ --gnu_version=100400 -DOLD_PAD Test_name.c
Loading