Skip to content

fix(folding): correct unique object rep checks [GH #327] - #326

Open
jakub-labenski wants to merge 1 commit into
edgcpp:mainfrom
jakub-labenski:has_unique_object_representations
Open

jakub-labenski wants to merge 1 commit into
edgcpp:mainfrom
jakub-labenski:has_unique_object_representations

Conversation

@jakub-labenski

Copy link
Copy Markdown

Discussion: #290

Fix __has_unique_object_representations for several cases:

  • A base class with no direct nonstatic data members that inherits some (and is thus not empty) was treated as an empty base. Its size was counted as tail padding, making the trait incorrectly FALSE for derived classes. Use is_empty_class_type instead of checking for an empty field list.

  • Treat unnamed bit-fields of nonzero width as padding in Clang 17+ and g++ 13.1+ (also g++ 10.5, 11.4, 12.3 backports).

  • Restrict treating volatile-qualified non-class types as lacking unique object representations to g++ modes before version 10, and no longer apply it in Clang modes.

Add regression test has-unique-object-rep-inherited-base and update expectations for imported Clang type-traits and g++ has-unique-obj-representations3 tests.

@nv-cmeerw nv-cmeerw left a comment

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.

Thats issue #327 now.

Comment thread src/Changes Outdated
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++:

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.

The issue is not actually gcc specific, but also applies to default/standard mode, so should just have an example with --c++11.

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.

Entry has been updated: --g++ was change to --c++11 and an empty message was added to static_assert.

Comment thread src/Changes Outdated
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

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.

What should the behavior for standard-mode be in this case?

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.

In standard mode, an unnamed bit-field of nonzero width is treated as padding, so __has_unique_object_representations(S) evaluates to false.

This was fixed in the latest update, along with new tests covering standard mode as well as GCC, Clang, and Microsoft emulation modes.

//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

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.

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.

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.

I've updated the tests to include standard mode and Microsoft emulation, and added the missing tests for the remaining changes.

Comment thread src/folding.c
field->source_corresp.assoc_info ==
(char *)get_unnamed_field_symbol()) {
/* An unnamed bit-field of non-zero width is padding. */
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.

@jakub-labenski
jakub-labenski force-pushed the has_unique_object_representations branch from c05bcb2 to 625b0c5 Compare October 21, 2026 08:11
@jakub-labenski

Copy link
Copy Markdown
Author

I'm not sure what the recommended practice is for syncing with main. I rebased the branch (and the pull request) onto main, then amended my commit to keep the git history clean.

Below is an AI-generated summary of the changes in my commit only:

  • Unnamed bit-fields: an unnamed bit-field of nonzero width now counts as padding by default, as the standard requires. In c05bcb2 this applied only to Clang 17+ and g++ 13.1+. The old behavior stays only in Clang modes before 17 and g++ modes before 13.1 (except the 10.5, 11.4 and 12.3 backports).
  • Unions: the unnamed bit-field rule no longer applies to unions; the existing union size check decides instead.
  • Microsoft mode: like Clang mode, it no longer treats a union bit-field narrower than the union as padding, matching MSVC.
  • Volatile check: the condition was rewritten as gpp_version_is(< 100000).
  • New tests: has-unique-object-rep-bit-field, -union-bit-field and -volatile. The -inherited-base test was tweaked, and expectations were updated.
  • src/Changes: the entry now carries the [GH #327] tag, and the examples use --c++11 with static_assert(..., "").

@jakub-labenski jakub-labenski changed the title fix(folding): correct unique object rep checks [] fix(folding): correct unique object rep checks [GH #327] Oct 21, 2026
@edgcpp-bot

Copy link
Copy Markdown
Collaborator

AcknowlEDG review results updated for 625b0c5a103e:

Comment thread src/Changes Outdated

This is now fixed. In addition:

- An unnamed bit-field of nonzero width is now treated as padding (making

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 we remove "(making the result FALSE), as the standard requires" here. I don't think it really adds much information, and the Changes entry is already quite long.

Comment thread src/Changes Outdated
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.

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.

Change that to a static_assert

Comment thread src/Changes Outdated
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

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.

I think this should just be added to the previous sentence with ", except in ..."

Comment thread src/Changes Outdated
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

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.

Change to a static_assert and move the --microsoft to "For example, with --microsoft".

Comment thread src/Changes Outdated
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.

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.

Maybe the second sentence can also be dropped?

//remark:has_unique_object_representations with unnamed bit-fields
//type:fp
//options_all:--c++11
//options:-DSTD_MODE:--g++ --gnu_version=90400 -DOLD_PAD:--g++ --gnu_version=100400 -DOLD_PAD:--g++ --gnu_version=100500:--g++ --gnu_version=120200 -DOLD_PAD:--g++ --gnu_version=120300:--g++ --gnu_version=150100:--clang --clang_version=160000 -DOLD_PAD:--clang --clang_version=170000:--microsoft

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.

Instead of adding macro definitions (STD_MODE, OLD_PAD), can we change the tests to check the GCC/Clang version macros directly. The idea here would be that the test case can be pasted into godbolt where it then should pass with any compiler selected (without having to adjust macro definitions).

Fix __has_unique_object_representations for several cases:

- A base class with no direct nonstatic data members that inherits
  some (and is thus not empty) was treated as an empty base. Its size
  was counted as tail padding, making the trait incorrectly FALSE for
  derived classes. Use is_empty_class_type instead of checking for an
  empty field list.

- Treat unnamed bit-fields of nonzero width in classes as padding, as
  the standard requires. Keep the old behavior only in Clang modes
  before 17 and g++ modes before 13.1 (except the 10.5, 11.4, and 12.3
  backports).

- Do not apply the unnamed bit-field rule to unions, where the bit-field
  overlaps the other members; the existing union size check decides.

- In Microsoft mode, as in Clang mode, do not treat a union bit-field
  narrower than the union as padding, matching MSVC.

- Restrict treating volatile-qualified non-class types as lacking
  unique object representations to g++ modes before version 10, and
  no longer apply it in Clang modes.

Add regression tests has-unique-object-rep-inherited-base,
has-unique-object-rep-bit-field, has-unique-object-rep-union-bit-field,
and has-unique-object-rep-volatile, covering standard, g++, Clang, and
Microsoft modes, and update expectations for imported Clang type-traits
and g++ has-unique-obj-representations3 tests.
@jakub-labenski
jakub-labenski force-pushed the has_unique_object_representations branch from 625b0c5 to f5ecadb Compare October 22, 2026 12:35
@edgcpp-bot

Copy link
Copy Markdown
Collaborator

AcknowlEDG review results updated for f5ecadb0bd7f:

CI other.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants