llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Peng Xie (love1angel)

<details>
<summary>Changes</summary>

P3074R7 makes union special member functions trivial by default in C++26, 
regardless of variant member triviality. A defaulted destructor for a union is 
now defined as deleted only if its default constructor is user-provided (or 
deleted/ambiguous), or if a variant member has both a default member 
initializer and a non-trivial destructor.

The pre-existing rule that a deleted or inaccessible member destructor causes 
the union destructor to be deleted (p7.2) is preserved.

This patch does not implement the implicit-lifetime-start semantics from 
P3074R7 p4, which was reworked by P3726R1 into __builtin_start_lifetime.

Defines __cpp_trivial_union=202502L (bumped to 202602L by P3726R1).

Close #<!-- -->127868 

Related #<!-- -->146815

ping @<!-- -->brevzin 

---

Patch is 40.28 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/185886.diff


9 Files Affected:

- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+6) 
- (modified) clang/lib/AST/DeclCXX.cpp (+24-5) 
- (modified) clang/lib/Frontend/InitPreprocessor.cpp (+4) 
- (modified) clang/lib/Sema/SemaDeclCXX.cpp (+133-2) 
- (modified) clang/test/CXX/drs/cwg14xx.cpp (+36-24) 
- (modified) clang/test/CXX/special/class.ctor/p5-0x.cpp (+9-7) 
- (modified) clang/test/CXX/special/class.ctor/p6-0x.cpp (+16-15) 
- (modified) clang/test/CXX/special/class.dtor/p5-0x.cpp (+17-16) 
- (added) clang/test/SemaCXX/cxx26-trivial-union.cpp (+251) 


``````````diff
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 0c25eb2443d5e..0cb33bc9511c3 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6406,6 +6406,12 @@ def note_enforce_read_only_placement : Note<"type was 
declared read-only here">;
 
 def note_deleted_dtor_no_operator_delete : Note<
   "virtual destructor requires an unambiguous, accessible 'operator delete'">;
+def note_deleted_dtor_default_ctor : Note<
+  "destructor of union %0 is implicitly deleted because "
+  "%select{it has no default constructor|"
+  "its default constructor is a deleted function|"
+  "overload resolution to default-initialize it is ambiguous|"
+  "its default constructor is not trivial}1">;
 def note_deleted_special_member_class_subobject : Note<
   "%select{default constructor of|copy constructor of|move constructor of|"
   "copy assignment operator of|move assignment operator of|destructor of|"
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 083c53e28cb91..6cb90e701fff4 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1180,7 +1180,11 @@ void CXXRecordDecl::addedMember(Decl *D) {
       // C++11 [class]p5:
       //   A default constructor is trivial if [...] no non-static data member
       //   of its class has a brace-or-equal-initializer.
-      data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor;
+      // P3074R7 [class.default.ctor]p3:
+      //   In C++26, a union's default constructor is always trivial,
+      //   even with brace-or-equal-initializers.
+      if (!(isUnion() && getASTContext().getLangOpts().CPlusPlus26))
+        data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor;
 
       // C++11 [dcl.init.aggr]p1:
       //   An aggregate is a [...] class with [...] no
@@ -1239,7 +1243,11 @@ void CXXRecordDecl::addedMember(Decl *D) {
           if (FieldRec->hasNonTrivialMoveAssignment())
             data().DefaultedMoveAssignmentIsDeleted = true;
           if (FieldRec->hasNonTrivialDestructor()) {
-            data().DefaultedDestructorIsDeleted = true;
+            // P3074R7: In C++26, the destructor of a union is not deleted
+            // merely because a variant member has a non-trivial destructor.
+            // Deletion is determined later by Sema based on the new rules.
+            if (!Context.getLangOpts().CPlusPlus26)
+              data().DefaultedDestructorIsDeleted = true;
             // C++20 [dcl.constexpr]p5:
             //   The definition of a constexpr destructor whose function-body 
is
             //   not = delete shall additionally satisfy...
@@ -1267,7 +1275,12 @@ void CXXRecordDecl::addedMember(Decl *D) {
         //    -- for all the non-static data members of its class that are of
         //       class type (or array thereof), each such class has a trivial
         //       default constructor.
-        if (!FieldRec->hasTrivialDefaultConstructor())
+        // P3074R7 [class.default.ctor]p3:
+        //   In C++26, "either X is a union or" for all non-variant
+        //   non-static data members [...] each such class has a trivial
+        //   default constructor.
+        if (!FieldRec->hasTrivialDefaultConstructor() &&
+            !(isUnion() && Context.getLangOpts().CPlusPlus26))
           data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor;
 
         // C++0x [class.copy]p13:
@@ -1305,9 +1318,15 @@ void CXXRecordDecl::addedMember(Decl *D) {
         if (!FieldRec->hasTrivialMoveAssignment())
           data().HasTrivialSpecialMembers &= ~SMF_MoveAssignment;
 
-        if (!FieldRec->hasTrivialDestructor())
+        // P3074R7 [class.dtor]p8:
+        //   In C++26, "either X is a union or" for all non-variant
+        //   non-static data members [...] each such class has a trivial
+        //   destructor.
+        if (!FieldRec->hasTrivialDestructor() &&
+            !(isUnion() && Context.getLangOpts().CPlusPlus26))
           data().HasTrivialSpecialMembers &= ~SMF_Destructor;
-        if (!FieldRec->hasTrivialDestructorForCall())
+        if (!FieldRec->hasTrivialDestructorForCall() &&
+            !(isUnion() && Context.getLangOpts().CPlusPlus26))
           data().HasTrivialSpecialMembersForCall &= ~SMF_Destructor;
         if (!FieldRec->hasIrrelevantDestructor())
           data().HasIrrelevantDestructor = false;
diff --git a/clang/lib/Frontend/InitPreprocessor.cpp 
b/clang/lib/Frontend/InitPreprocessor.cpp
index 1ccd74314f373..a00b34625510b 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -746,6 +746,10 @@ static void InitializeCPlusPlusFeatureTestMacros(const 
LangOptions &LangOpts,
   Builder.defineMacro("__cpp_variadic_friend", "202403L");
   Builder.defineMacro("__cpp_trivial_relocatability", "202502L");
 
+  // C++26 features.
+  if (LangOpts.CPlusPlus26)
+    Builder.defineMacro("__cpp_trivial_union", "202502L");
+
   if (LangOpts.Char8)
     Builder.defineMacro("__cpp_char8_t", "202207L");
   Builder.defineMacro("__cpp_impl_destroying_delete", "201806L");
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 2ae6e5de0e3ee..c316eca5fc72e 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -9615,6 +9615,12 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
   if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted) {
     if (CSM == CXXSpecialMemberKind::DefaultConstructor && Field &&
         Field->getParent()->isUnion()) {
+      // P3074R7: In C++26, a union's defaulted default constructor is never
+      // deleted due to a variant member with a non-trivial default
+      // constructor. The old [class.default.ctor]p2 union-specific bullets
+      // are removed.
+      if (S.getLangOpts().CPlusPlus26)
+        return false;
       // [class.default.ctor]p2:
       //   A defaulted default constructor for class X is defined as deleted if
       //   - X is a union that has a variant member with a non-trivial default
@@ -9637,6 +9643,11 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
     // destructor is never actually called, but is semantically checked as
     // if it were.
     if (CSM == CXXSpecialMemberKind::DefaultConstructor) {
+      // P3074R7: In C++26, a union's defaulted default constructor is never
+      // deleted due to a variant member with a non-trivial default
+      // constructor.
+      if (S.getLangOpts().CPlusPlus26)
+        return false;
       // [class.default.ctor]p2:
       //   A defaulted default constructor for class X is defined as deleted if
       //   - X is a union that has a variant member with a non-trivial default
@@ -9645,6 +9656,13 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
       const auto *RD = cast<CXXRecordDecl>(Field->getParent());
       if (!RD->hasInClassInitializer())
         DiagKind = NonTrivialDecl;
+    } else if (CSM == CXXSpecialMemberKind::Destructor &&
+               S.getLangOpts().CPlusPlus26) {
+      // P3074R7 [class.dtor]p7: In C++26, a union's destructor is not
+      // deleted merely because a variant member has a non-trivial destructor.
+      // Deletion is determined by the new union-specific rules in
+      // ShouldDeleteSpecialMember.
+      return false;
     } else {
       DiagKind = NonTrivialDecl;
     }
@@ -9806,6 +9824,12 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
   if (inUnion() && shouldDeleteForVariantPtrAuthMember(FD))
     return true;
 
+  // P3074R7: In C++26, a union's defaulted default constructor is trivially
+  // defined and never deleted due to variant member properties.
+  if (inUnion() && S.getLangOpts().CPlusPlus26 &&
+      CSM == CXXSpecialMemberKind::DefaultConstructor)
+    return false;
+
   if (CSM == CXXSpecialMemberKind::DefaultConstructor) {
     // For a default constructor, all references must be initialized in-class
     // and, if a union, it must have a non-const member.
@@ -9884,7 +9908,8 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
 
       // At least one member in each anonymous union must be non-const
       if (CSM == CXXSpecialMemberKind::DefaultConstructor &&
-          AllVariantFieldsAreConst && !FieldRecord->field_empty()) {
+          AllVariantFieldsAreConst && !FieldRecord->field_empty() &&
+          !S.getLangOpts().CPlusPlus26) {
         if (Diagnose)
           S.Diag(FieldRecord->getLocation(),
                  diag::note_deleted_default_ctor_all_const)
@@ -9914,6 +9939,8 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForAllConstMembers() {
   // default constructor. Don't do that.
   if (CSM == CXXSpecialMemberKind::DefaultConstructor && inUnion() &&
       AllFieldsAreConst) {
+    if (S.getLangOpts().CPlusPlus26)
+      return false;
     bool AnyFields = false;
     for (auto *F : MD->getParent()->fields())
       if ((AnyFields = !F->isUnnamedBitField()))
@@ -10034,6 +10061,100 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl 
*MD,
 
   SpecialMemberDeletionInfo SMI(*this, MD, CSM, ICI, Diagnose);
 
+  // P3074R7 [class.dtor]p7.x:
+  // In C++26, a defaulted destructor for a union X is defined as deleted if:
+  //   (7.x.1) overload resolution to select a constructor to
+  //           default-initialize an object of type X either fails or selects
+  //           a constructor that is either deleted or not trivial, or
+  //   (7.x.2) X has a variant member V of class type M (or possibly
+  //           multi-dimensional array thereof) where V has a default member
+  //           initializer and M has a destructor that is non-trivial.
+  // Note: p7.2 (deleted/inaccessible member dtor) still applies to unions.
+  // We handle 7.x.1 and 7.x.2 here and fall through to the normal
+  // per-member visit for p7.2 checking. shouldDeleteForSubobjectCall
+  // already returns false for non-trivial-but-not-deleted dtors in C++26
+  // unions, so only truly deleted/inaccessible dtors will cause deletion
+  // through the member visit.
+  if (getLangOpts().CPlusPlus26 && RD->isUnion() &&
+      CSM == CXXSpecialMemberKind::Destructor) {
+    // Check (7.x.1): overload resolution for default initialization.
+    SpecialMemberOverloadResult SMOR = LookupSpecialMember(
+        RD, CXXSpecialMemberKind::DefaultConstructor,
+        /*ConstArg=*/false, /*VolatileArg=*/false, /*RValueThis=*/false,
+        /*ConstThis=*/false, /*VolatileThis=*/false);
+    bool CtorOK = false;
+    if (SMOR.getKind() == SpecialMemberOverloadResult::Success) {
+      auto *Ctor = cast<CXXConstructorDecl>(SMOR.getMethod());
+      // In C++26, union default ctors are trivial unless user-provided
+      // (P3074R7 [class.default.ctor]p3). We use !isUserProvided() rather
+      // than isTrivial() because the triviality flag may not be set yet for
+      // explicitly defaulted ctors at the point DeclareImplicitDestructor
+      // runs during class completion.
+      CtorOK = !Ctor->isDeleted() && !Ctor->isUserProvided();
+    } else if (SMOR.getKind() ==
+               SpecialMemberOverloadResult::NoMemberOrDeleted) {
+      if (!SMOR.getMethod()) {
+        // No default constructor exists (e.g. suppressed by user-declared
+        // constructors, or no viable candidate for 0 args). The union
+        // cannot be default-initialized, so rule 7.x.1 does not apply.
+        CtorOK = true;
+      }
+      // else: a deleted default ctor was selected → CtorOK stays false.
+    }
+    // Ambiguous → CtorOK stays false.
+    if (!CtorOK) {
+      // 7.x.1: OR is ambiguous, selects a deleted ctor, or selects a
+      // non-trivial (user-provided) ctor.
+      if (Diagnose) {
+        unsigned Reason;
+        if (SMOR.getKind() == SpecialMemberOverloadResult::Ambiguous)
+          Reason = 2; // ambiguous
+        else if (SMOR.getKind() ==
+                 SpecialMemberOverloadResult::NoMemberOrDeleted) {
+          auto *Ctor = SMOR.getMethod();
+          Reason = (Ctor && Ctor->isDeleted()) ? 1 : 0;
+        } else {
+          Reason = 3; // not trivial
+        }
+        Diag(RD->getLocation(), diag::note_deleted_dtor_default_ctor)
+            << RD << Reason;
+      }
+      return true;
+    }
+    // Ctor is OK. Check (7.x.2): walk variant members (including through
+    // anonymous structs) for DMI + non-trivial dtor.
+    std::function<bool(const CXXRecordDecl *)> HasDMINonTrivDtor =
+        [&](const CXXRecordDecl *Record) -> bool {
+      for (const auto *FD : Record->fields()) {
+        if (FD->hasInClassInitializer()) {
+          QualType FT = Context.getBaseElementType(FD->getType());
+          if (const auto *FR = FT->getAsCXXRecordDecl()) {
+            if (FR->hasNonTrivialDestructor()) {
+              if (Diagnose)
+                Diag(FD->getLocation(),
+                     diag::note_deleted_special_member_class_subobject)
+                    << getSpecialMember(MD) << RD << /*IsField*/ true << FD
+                    << /*NonTrivialDecl*/ 4 << /*IsDtorCallInCtor*/ false
+                    << /*IsObjCPtr*/ false;
+              return true;
+            }
+          }
+        }
+        if (FD->isAnonymousStructOrUnion()) {
+          if (const auto *SubRD = FD->getType()->getAsCXXRecordDecl()) {
+            if (HasDMINonTrivDtor(SubRD))
+              return true;
+          }
+        }
+      }
+      return false;
+    };
+    if (HasDMINonTrivDtor(RD))
+      return true;
+    // Neither 7.x.1 nor 7.x.2 triggered. Fall through to the normal
+    // per-member visit for p7.2 (deleted/inaccessible dtor) checking.
+  }
+
   // Per DR1611, do not consider virtual bases of constructors of abstract
   // classes, since we are not going to construct them.
   // Per DR1658, do not consider virtual bases of destructors of abstract
@@ -10467,7 +10588,17 @@ bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, 
CXXSpecialMemberKind CSM,
   //    -- for all of the non-static data members of its class that are of 
class
   //       type (or array thereof), each such class has a trivial [default
   //       constructor or destructor]
-  if (!checkTrivialClassMembers(*this, RD, CSM, ConstArg, TAH, Diagnose))
+  //
+  // P3074R7 [class.default.ctor]p3, [class.dtor]p8:
+  //   In C++26, "either X is a union or" the above member checks apply.
+  //   For unions, default constructor and destructor are trivial regardless
+  //   of member triviality.
+  if (RD->isUnion() && getLangOpts().CPlusPlus26 &&
+      (CSM == CXXSpecialMemberKind::DefaultConstructor ||
+       CSM == CXXSpecialMemberKind::Destructor)) {
+    // Union default ctor and destructor are trivial in C++26 per P3074.
+    // Skip member triviality checks.
+  } else if (!checkTrivialClassMembers(*this, RD, CSM, ConstArg, TAH, 
Diagnose))
     return false;
 
   // C++11 [class.dtor]p5:
diff --git a/clang/test/CXX/drs/cwg14xx.cpp b/clang/test/CXX/drs/cwg14xx.cpp
index dba1850ce8df9..fa9b866d6bfcd 100644
--- a/clang/test/CXX/drs/cwg14xx.cpp
+++ b/clang/test/CXX/drs/cwg14xx.cpp
@@ -1,18 +1,18 @@
 // RUN: %clang_cc1 -std=c++98 %s -verify=expected -fexceptions 
-fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++11 %s -verify=expected,cxx11-17,since-cxx11, 
-fexceptions -fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++14 %s 
-verify=expected,cxx14-17,cxx11-17,since-cxx11,since-cxx14 -fexceptions 
-fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++17 %s 
-verify=expected,cxx14-17,cxx11-17,since-cxx11,since-cxx14 -fexceptions 
-fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++20 %s 
-verify=expected,since-cxx11,since-cxx14,since-cxx20 -fexceptions 
-fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++23 %s 
-verify=expected,since-cxx11,since-cxx14,since-cxx20 -fexceptions 
-fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++2c %s 
-verify=expected,since-cxx11,since-cxx14,since-cxx20 -fexceptions 
-fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++11 %s 
-verify=expected,cxx11-17,since-cxx11,precxx26 -fexceptions -fcxx-exceptions 
-pedantic-errors
+// RUN: %clang_cc1 -std=c++14 %s 
-verify=expected,cxx14-17,cxx11-17,since-cxx11,since-cxx14,precxx26 
-fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++17 %s 
-verify=expected,cxx14-17,cxx11-17,since-cxx11,since-cxx14,precxx26 
-fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++20 %s 
-verify=expected,since-cxx11,since-cxx14,since-cxx20,precxx26 -fexceptions 
-fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++23 %s 
-verify=expected,since-cxx11,since-cxx14,since-cxx20,precxx26 -fexceptions 
-fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++2c %s 
-verify=expected,since-cxx11,since-cxx14,since-cxx20,since-cxx26 -fexceptions 
-fcxx-exceptions -pedantic-errors
 
 // RUN: %clang_cc1 -std=c++98 %s -verify=expected -fexceptions 
-fcxx-exceptions -pedantic-errors -fexperimental-new-constant-interpreter
-// RUN: %clang_cc1 -std=c++11 %s -verify=expected,cxx11-17,since-cxx11, 
-fexceptions -fcxx-exceptions -pedantic-errors 
-fexperimental-new-constant-interpreter
-// RUN: %clang_cc1 -std=c++14 %s 
-verify=expected,cxx14-17,cxx11-17,since-cxx11,since-cxx14 -fexceptions 
-fcxx-exceptions -pedantic-errors -fexperimental-new-constant-interpreter
-// RUN: %clang_cc1 -std=c++17 %s 
-verify=expected,cxx14-17,cxx11-17,since-cxx11,since-cxx14 -fexceptions 
-fcxx-exceptions -pedantic-errors -fexperimental-new-constant-interpreter
-// RUN: %clang_cc1 -std=c++20 %s 
-verify=expected,since-cxx11,since-cxx14,since-cxx20 -fexceptions 
-fcxx-exceptions -pedantic-errors -fexperimental-new-constant-interpreter
-// RUN: %clang_cc1 -std=c++23 %s 
-verify=expected,since-cxx11,since-cxx14,since-cxx20 -fexceptions 
-fcxx-exceptions -pedantic-errors -fexperimental-new-constant-interpreter
-// RUN: %clang_cc1 -std=c++2c %s 
-verify=expected,since-cxx11,since-cxx14,since-cxx20 -fexceptions 
-fcxx-exceptions -pedantic-errors -fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 -std=c++11 %s 
-verify=expected,cxx11-17,since-cxx11,precxx26 -fexceptions -fcxx-exceptions 
-pedantic-errors -fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 -std=c++14 %s 
-verify=expected,cxx14-17,cxx11-17,since-cxx11,since-cxx14,precxx26 
-fexceptions -fcxx-exceptions -pedantic-errors 
-fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 -std=c++17 %s 
-verify=expected,cxx14-17,cxx11-17,since-cxx11,since-cxx14,precxx26 
-fexceptions -fcxx-exceptions -pedantic-errors 
-fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 -std=c++20 %s 
-verify=expected,since-cxx11,since-cxx14,since-cxx20,precxx26 -fexceptions 
-fcxx-exceptions -pedantic-errors -fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 -std=c++23 %s 
-verify=expected,since-cxx11,since-cxx14,since-cxx20,precxx26 -fexceptions 
-fcxx-exceptions -pedantic-errors -fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 -std=c++2c %s 
-verify=expected,since-cxx11,since-cxx14,since-cxx20,since-cxx26 -fexceptions 
-fcxx-exceptions -pedantic-errors -fexperimental-new-constant-interpreter
 
 namespace cwg1413 { // cwg1413: 12
   template<int> struct Check {
@@ -128,7 +128,7 @@ struct A {
 namespace cwg1460 { // cwg1460: 3.5
 #if __cplusplus >= 201103L
   namespace DRExample {
-    union A {
+    union A { // #cwg1460-DRExample-A
       union {};
       // since-cxx11-error@-1 {{declaration does not declare anything}}
       union {};
@@ -136,6 +136,8 @@ namespace cwg1460 { // cwg1460: 3.5
       constexpr A() {}
     };
     constexpr A a = A();
+    // since-cxx26-error@-1 {{attempt to use a deleted function}}
+    //   since-cxx26-note@#cwg1460-DRExample-A {{destructor of union 'A' is 
implicitly deleted because its default constructor is not trivial}}
 
     union B {
       union {};
@@ -277,32 +279,42 @@ namespace cwg1460 { // cwg1460: 3.5
     };
     static_assert(A().a == 1 && A().b == 2 && A().c == 3, "");
 
-    union B {
+    union B { // #cwg1460-Overriding-B
       int a, b = 2, c;
       constexpr B() : a(1) {}
       constexpr B(char) : b(4) {}
       constexpr B(int) : c(3) {}
       constexpr B(const char*) {}
     };
+    // since-cxx26-note@#cwg1460-Overriding-B 9 {{destructor of union 'B' is 
implicitly deleted because its default constructor is not trivial}}
     static_assert(B().a == 1, "");
+    // since-cxx...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/185886
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to