[clang] [clang] Allow class with anonymous union member to be const-default-constructible even if a union member has a default member initializer (#95854) (PR #96301)

Rajveer Singh Bharadwaj via cfe-commits cfe-commits at lists.llvm.org
Fri Jul 5 04:08:16 PDT 2024


https://github.com/Rajveer100 updated https://github.com/llvm/llvm-project/pull/96301

>From 3fb29e52b7227c2778942b3ca941112596ce89c1 Mon Sep 17 00:00:00 2001
From: Rajveer <rajveer.developer at icloud.com>
Date: Fri, 21 Jun 2024 18:26:36 +0530
Subject: [PATCH] [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
---
 clang/docs/ReleaseNotes.rst       |  6 ++++++
 clang/include/clang/AST/DeclCXX.h |  3 ++-
 clang/lib/AST/DeclCXX.cpp         |  9 ++++++++-
 clang/test/SemaCXX/GH95854.cpp    | 21 +++++++++++++++++++++
 4 files changed, 37 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/SemaCXX/GH95854.cpp

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 45676a02b760b..c107304ea95f7 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -624,6 +624,12 @@ Bug Fixes in This Version
 
 - ``__is_array`` and ``__is_bounded_array`` no longer return ``true`` for
   zero-sized arrays. Fixes (#GH54705).
+  
+- 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).
 
 Bug Fixes to Compiler Builtins
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index fb52ac804849d..f4d90e19e0e05 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -1392,7 +1392,8 @@ class CXXRecordDecl : public RecordDecl {
   bool allowConstDefaultInit() const {
     return !data().HasUninitializedFields ||
            !(data().HasDefaultedDefaultConstructor ||
-             needsImplicitDefaultConstructor());
+             needsImplicitDefaultConstructor()) ||
+           (isUnion() && isEmpty());
   }
 
   /// Determine whether this class has a destructor which has no
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 75c441293d62e..0b963cb305d27 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1018,6 +1018,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
@@ -1086,7 +1089,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;
diff --git a/clang/test/SemaCXX/GH95854.cpp b/clang/test/SemaCXX/GH95854.cpp
new file mode 100644
index 0000000000000..62ae549f2496f
--- /dev/null
+++ b/clang/test/SemaCXX/GH95854.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify %s
+//
+// -expected-no-diagnostics
+
+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}}



More information about the cfe-commits mailing list