Skip to content

Commit

Permalink
[clang] Allow class with anonymous union member to be const-default-c…
Browse files Browse the repository at this point in the history
…onstructible even if a union member has a default member initializer (llvm#95854)

Resolves llvm#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.

```
struct A {
  union {
    int n = 0;
    int m;
  };
};
const A a;
```

-- As per https://eel.is/c++draft/dcl.init#general-8.3
  • Loading branch information
Rajveer100 committed Aug 13, 2024
1 parent 64d9713 commit b46a96d
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 3 deletions.
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,9 @@ Bug Fixes to C++ Support
- Fixed a bug when diagnosing ambiguous explicit specializations of constrained member functions.
- Fixed an assertion failure when selecting a function from an overload set that includes a
specialization of a conversion function template.
- 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.
(#GH95854).

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
5 changes: 3 additions & 2 deletions clang/include/clang/AST/DeclCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -1161,8 +1161,9 @@ class CXXRecordDecl : public RecordDecl {
/// value-initialized [...] A program that calls for [...]
/// value-initialization of an entity of reference type is ill-formed.
bool hasUninitializedReferenceMember() const {
return !isUnion() && !hasUserDeclaredConstructor() &&
data().HasUninitializedReferenceMember;
return (!isUnion() && !hasUserDeclaredConstructor() &&
data().HasUninitializedReferenceMember) ||
needsImplicitDefaultConstructor();
}

/// Whether this class is a POD-type (C++ [class]p4)
Expand Down
9 changes: 8 additions & 1 deletion clang/lib/AST/DeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1057,6 +1057,9 @@ void CXXRecordDecl::addedMember(Decl *D) {
if (isUnion() && !Field->isAnonymousStructOrUnion())
data().HasVariantMembers = true;

if (isUnion() && IsFirstField)
data().HasUninitializedFields = true;

// C++0x [class]p9:
// A POD struct is a class that is both a trivial class and a
// standard-layout class, and has no non-static data members of type
Expand Down Expand Up @@ -1125,7 +1128,11 @@ void CXXRecordDecl::addedMember(Decl *D) {
data().DefaultedCopyConstructorIsDeleted = true;
}

if (!Field->hasInClassInitializer() && !Field->isMutable()) {
if (isUnion() && !Field->isMutable()) {
if (Field->hasInClassInitializer()) {
data().HasUninitializedFields = false;
}
} else if (!Field->hasInClassInitializer() && !Field->isMutable()) {
if (CXXRecordDecl *FieldType = T->getAsCXXRecordDecl()) {
if (FieldType->hasDefinition() && !FieldType->allowConstDefaultInit())
data().HasUninitializedFields = true;
Expand Down
19 changes: 19 additions & 0 deletions clang/test/SemaCXX/GH95854.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify %s

struct A {
union {
int n = 0;
int m;
};
};
const A a;

struct B {
union {
struct {
int n = 5;
int m;
};
};
};
const B b; // expected-error {{default initialization of an object of const type 'const B' without a user-provided default constructor}}

0 comments on commit b46a96d

Please sign in to comment.