Skip to content

Commit 751e630

Browse files
committed
[clang] Allow class with anonymous union member to be const-default-constructible even if a union member has a default member initializer (#95854)
Resolves #95854 Clang incorrectly considers a class with an anonymous union member to not be const-default-constructible even if a union member has a default member initializer. This is valid as per ``8.3`` in `Draft C++ Standard <https://eel.is/c++draft/dcl.init#general-8.3>`_. The ``allowConstDefaultInit`` member function in ``CXXRecordDecl`` needs special-case unions to handle the rule. (#GH95854). ``` struct A { union { int n = 0; int m; }; }; const A a; ``` -- As per https://eel.is/c++draft/dcl.init#general-8.3
1 parent 00c622e commit 751e630

File tree

4 files changed

+37
-2
lines changed

4 files changed

+37
-2
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -756,6 +756,12 @@ Bug Fixes in This Version
756756

757757
- ``__is_array`` and ``__is_bounded_array`` no longer return ``true`` for
758758
zero-sized arrays. Fixes (#GH54705).
759+
760+
- Clang incorrectly considers a class with an anonymous union member to not be
761+
const-default-constructible even if a union member has a default member initializer.
762+
This is valid as per ``8.3`` in `Draft C++ Standard <https://eel.is/c++draft/dcl.init#general-8.3>`_.
763+
The ``allowConstDefaultInit`` member function in ``CXXRecordDecl`` needs
764+
special-case unions to handle the rule. (#GH95854).
759765

760766
- Correctly reject declarations where a statement is required in C.
761767
Fixes #GH92775

clang/include/clang/AST/DeclCXX.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1392,7 +1392,8 @@ class CXXRecordDecl : public RecordDecl {
13921392
bool allowConstDefaultInit() const {
13931393
return !data().HasUninitializedFields ||
13941394
!(data().HasDefaultedDefaultConstructor ||
1395-
needsImplicitDefaultConstructor());
1395+
needsImplicitDefaultConstructor()) ||
1396+
(isUnion() && isEmpty());
13961397
}
13971398

13981399
/// Determine whether this class has a destructor which has no

clang/lib/AST/DeclCXX.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1018,6 +1018,9 @@ void CXXRecordDecl::addedMember(Decl *D) {
10181018
if (isUnion() && !Field->isAnonymousStructOrUnion())
10191019
data().HasVariantMembers = true;
10201020

1021+
if (isUnion() && IsFirstField)
1022+
data().HasUninitializedFields = true;
1023+
10211024
// C++0x [class]p9:
10221025
// A POD struct is a class that is both a trivial class and a
10231026
// standard-layout class, and has no non-static data members of type
@@ -1086,7 +1089,11 @@ void CXXRecordDecl::addedMember(Decl *D) {
10861089
data().DefaultedCopyConstructorIsDeleted = true;
10871090
}
10881091

1089-
if (!Field->hasInClassInitializer() && !Field->isMutable()) {
1092+
if (isUnion() && !Field->isMutable()) {
1093+
if (Field->hasInClassInitializer()) {
1094+
data().HasUninitializedFields = false;
1095+
}
1096+
} else if (!Field->hasInClassInitializer() && !Field->isMutable()) {
10901097
if (CXXRecordDecl *FieldType = T->getAsCXXRecordDecl()) {
10911098
if (FieldType->hasDefinition() && !FieldType->allowConstDefaultInit())
10921099
data().HasUninitializedFields = true;

clang/test/SemaCXX/GH95854.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify %s
2+
//
3+
// -expected-no-diagnostics
4+
5+
struct A {
6+
union {
7+
int n = 0;
8+
int m;
9+
};
10+
};
11+
const A a;
12+
13+
struct B {
14+
union {
15+
struct {
16+
int n = 5;
17+
int m;
18+
};
19+
};
20+
};
21+
const B b; // expected-error {{default initialization of an object of const type 'const B' without a user-provided default constructor}}

0 commit comments

Comments
 (0)