[clang] [clang][Sema] Track trivial-relocatability as a type trait (PR #84621)

2024-04-05 Thread Barry Revzin via cfe-commits


@@ -857,8 +881,13 @@ void CXXRecordDecl::addedMember(Decl *D) {
 data().HasDeclaredCopyAssignmentWithConstParam = true;
 }
 
-if (Method->isMoveAssignmentOperator())
+if (Method->isMoveAssignmentOperator()) {
   SMKind |= SMF_MoveAssignment;
+}
+
+if (Method->isUserProvided() &&
+(Method->isCopyAssignment() || Method->isMoveAssignment()))
+  data().IsNaturallyTriviallyRelocatable = false;

brevzin wrote:

> Only "stupid types" will have a trivial copy/move constructor and a 
> non-trivial assignment operator that does something different.

One such type is `std::tuple`. As far as I can tell, the way the 
different papers handle this type is:

* P1144: not trivially relocatable (because the copy/move assignment operator 
is user-provided)
* P2786: trivially relocatable (because we only care about move construction, 
and that one is defaulted)

I don't actually know what goes wrong (if anything) if you make `tuple` 
trivially relocatable, but at least that's a nice concrete example to think 
about. 

https://github.com/llvm/llvm-project/pull/84621
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [P3074] Partial implementation of support for trivial unions (PR #146815)

2025-07-03 Thread Barry Revzin via cfe-commits

https://github.com/brevzin updated 
https://github.com/llvm/llvm-project/pull/146815

>From 40290a957b6f349a9b670193c8bc699d8eb7d373 Mon Sep 17 00:00:00 2001
From: Barry Revzin 
Date: Fri, 27 Jun 2025 17:29:45 -0500
Subject: [PATCH 1/8] [P3074] Implementing part of trivial unions

---
 clang/lib/AST/DeclCXX.cpp   |  9 --
 clang/lib/Sema/SemaDeclCXX.cpp  | 16 +-
 clang/test/CXX/drs/cwg6xx.cpp   |  4 +--
 clang/test/CXX/special/class.ctor/p5-0x.cpp | 15 +-
 clang/test/CXX/special/class.ctor/p6-0x.cpp | 28 +
 clang/test/CXX/special/class.dtor/p5-0x.cpp | 33 +++--
 6 files changed, 63 insertions(+), 42 deletions(-)

diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index ccb308e103253..49adbdf1c393d 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1217,6 +1217,9 @@ void CXXRecordDecl::addedMember(Decl *D) {
 // those because they are always unnamed.
 bool IsZeroSize = Field->isZeroSize(Context);
 
+// P3074
+const bool TrivialUnion = Context.getLangOpts().CPlusPlus26 && isUnion();
+
 if (const auto *RecordTy = T->getAs()) {
   auto *FieldRec = cast(RecordTy->getDecl());
   if (FieldRec->getDefinition()) {
@@ -1277,7 +1280,7 @@ 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())
+if (!FieldRec->hasTrivialDefaultConstructor() && !TrivialUnion)
   data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor;
 
 // C++0x [class.copy]p13:
@@ -1315,9 +1318,9 @@ void CXXRecordDecl::addedMember(Decl *D) {
 if (!FieldRec->hasTrivialMoveAssignment())
   data().HasTrivialSpecialMembers &= ~SMF_MoveAssignment;
 
-if (!FieldRec->hasTrivialDestructor())
+if (!FieldRec->hasTrivialDestructor() && !TrivialUnion)
   data().HasTrivialSpecialMembers &= ~SMF_Destructor;
-if (!FieldRec->hasTrivialDestructorForCall())
+if (!FieldRec->hasTrivialDestructorForCall() && !TrivialUnion)
   data().HasTrivialSpecialMembersForCall &= ~SMF_Destructor;
 if (!FieldRec->hasIrrelevantDestructor())
   data().HasIrrelevantDestructor = false;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index e8c65025bfe6d..225409a69df53 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -9511,6 +9511,15 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
   CXXMethodDecl *Decl = SMOR.getMethod();
   FieldDecl *Field = Subobj.dyn_cast();
 
+  // P3074: default ctor and dtor for unions are not deleted, regardless of
+  // whether the underlying fields have non-trivial or deleted versions of 
those
+  // members
+  if (S.Context.getLangOpts().CPlusPlus26)
+if (Field && Field->getParent()->isUnion() &&
+(CSM == CXXSpecialMemberKind::DefaultConstructor ||
+ CSM == CXXSpecialMemberKind::Destructor))
+  return false;
+
   int DiagKind = -1;
 
   if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted)
@@ -9774,7 +9783,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.Context.getLangOpts().CPlusPlus26) {
 if (Diagnose)
   S.Diag(FieldRecord->getLocation(),
  diag::note_deleted_default_ctor_all_const)
@@ -9804,6 +9814,10 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForAllConstMembers() {
   // default constructor. Don't do that.
   if (CSM == CXXSpecialMemberKind::DefaultConstructor && inUnion() &&
   AllFieldsAreConst) {
+
+if (S.Context.getLangOpts().CPlusPlus26)
+  return false;
+
 bool AnyFields = false;
 for (auto *F : MD->getParent()->fields())
   if ((AnyFields = !F->isUnnamedBitField()))
diff --git a/clang/test/CXX/drs/cwg6xx.cpp b/clang/test/CXX/drs/cwg6xx.cpp
index e2eb009508b52..dd54bb5295b56 100644
--- a/clang/test/CXX/drs/cwg6xx.cpp
+++ b/clang/test/CXX/drs/cwg6xx.cpp
@@ -4,7 +4,7 @@
 // RUN: %clang_cc1 -std=c++17 %s 
-verify=expected,cxx11-20,cxx98-17,cxx11-17,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
 // RUN: %clang_cc1 -std=c++20 %s -verify=expected,cxx11-20,since-cxx11 
-fexceptions -fcxx-exceptions -pedantic-errors
 // RUN: %clang_cc1 -std=c++23 %s -verify=expected,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++2c %s -verify=expected,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc

[clang] [P3074] Partial implementation of support for trivial unions (PR #146815)

2025-07-03 Thread Barry Revzin via cfe-commits

https://github.com/brevzin updated 
https://github.com/llvm/llvm-project/pull/146815

>From 40290a957b6f349a9b670193c8bc699d8eb7d373 Mon Sep 17 00:00:00 2001
From: Barry Revzin 
Date: Fri, 27 Jun 2025 17:29:45 -0500
Subject: [PATCH 1/9] [P3074] Implementing part of trivial unions

---
 clang/lib/AST/DeclCXX.cpp   |  9 --
 clang/lib/Sema/SemaDeclCXX.cpp  | 16 +-
 clang/test/CXX/drs/cwg6xx.cpp   |  4 +--
 clang/test/CXX/special/class.ctor/p5-0x.cpp | 15 +-
 clang/test/CXX/special/class.ctor/p6-0x.cpp | 28 +
 clang/test/CXX/special/class.dtor/p5-0x.cpp | 33 +++--
 6 files changed, 63 insertions(+), 42 deletions(-)

diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index ccb308e103253..49adbdf1c393d 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1217,6 +1217,9 @@ void CXXRecordDecl::addedMember(Decl *D) {
 // those because they are always unnamed.
 bool IsZeroSize = Field->isZeroSize(Context);
 
+// P3074
+const bool TrivialUnion = Context.getLangOpts().CPlusPlus26 && isUnion();
+
 if (const auto *RecordTy = T->getAs()) {
   auto *FieldRec = cast(RecordTy->getDecl());
   if (FieldRec->getDefinition()) {
@@ -1277,7 +1280,7 @@ 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())
+if (!FieldRec->hasTrivialDefaultConstructor() && !TrivialUnion)
   data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor;
 
 // C++0x [class.copy]p13:
@@ -1315,9 +1318,9 @@ void CXXRecordDecl::addedMember(Decl *D) {
 if (!FieldRec->hasTrivialMoveAssignment())
   data().HasTrivialSpecialMembers &= ~SMF_MoveAssignment;
 
-if (!FieldRec->hasTrivialDestructor())
+if (!FieldRec->hasTrivialDestructor() && !TrivialUnion)
   data().HasTrivialSpecialMembers &= ~SMF_Destructor;
-if (!FieldRec->hasTrivialDestructorForCall())
+if (!FieldRec->hasTrivialDestructorForCall() && !TrivialUnion)
   data().HasTrivialSpecialMembersForCall &= ~SMF_Destructor;
 if (!FieldRec->hasIrrelevantDestructor())
   data().HasIrrelevantDestructor = false;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index e8c65025bfe6d..225409a69df53 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -9511,6 +9511,15 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
   CXXMethodDecl *Decl = SMOR.getMethod();
   FieldDecl *Field = Subobj.dyn_cast();
 
+  // P3074: default ctor and dtor for unions are not deleted, regardless of
+  // whether the underlying fields have non-trivial or deleted versions of 
those
+  // members
+  if (S.Context.getLangOpts().CPlusPlus26)
+if (Field && Field->getParent()->isUnion() &&
+(CSM == CXXSpecialMemberKind::DefaultConstructor ||
+ CSM == CXXSpecialMemberKind::Destructor))
+  return false;
+
   int DiagKind = -1;
 
   if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted)
@@ -9774,7 +9783,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.Context.getLangOpts().CPlusPlus26) {
 if (Diagnose)
   S.Diag(FieldRecord->getLocation(),
  diag::note_deleted_default_ctor_all_const)
@@ -9804,6 +9814,10 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForAllConstMembers() {
   // default constructor. Don't do that.
   if (CSM == CXXSpecialMemberKind::DefaultConstructor && inUnion() &&
   AllFieldsAreConst) {
+
+if (S.Context.getLangOpts().CPlusPlus26)
+  return false;
+
 bool AnyFields = false;
 for (auto *F : MD->getParent()->fields())
   if ((AnyFields = !F->isUnnamedBitField()))
diff --git a/clang/test/CXX/drs/cwg6xx.cpp b/clang/test/CXX/drs/cwg6xx.cpp
index e2eb009508b52..dd54bb5295b56 100644
--- a/clang/test/CXX/drs/cwg6xx.cpp
+++ b/clang/test/CXX/drs/cwg6xx.cpp
@@ -4,7 +4,7 @@
 // RUN: %clang_cc1 -std=c++17 %s 
-verify=expected,cxx11-20,cxx98-17,cxx11-17,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
 // RUN: %clang_cc1 -std=c++20 %s -verify=expected,cxx11-20,since-cxx11 
-fexceptions -fcxx-exceptions -pedantic-errors
 // RUN: %clang_cc1 -std=c++23 %s -verify=expected,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++2c %s -verify=expected,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc

[clang] [Clang] Partial implementation of support for P3074 (trivial unions) (PR #146815)

2025-07-07 Thread Barry Revzin via cfe-commits

https://github.com/brevzin edited 
https://github.com/llvm/llvm-project/pull/146815
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Partial implementation of support for P3074 (trivial unions) (PR #146815)

2025-07-07 Thread Barry Revzin via cfe-commits


@@ -9543,6 +9543,48 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
   if (DiagKind == -1)
 return false;
 
+  if (this->S.Context.getLangOpts().CPlusPlus26 && inUnion() &&
+  CSM == CXXSpecialMemberKind::Destructor) {
+// [class.dtor]/7 In C++26, a destructor for a union X is only deleted 
under
+// the additional conditions that:
+
+// 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
+// or 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,
+
+RecordDecl *Parent = Field->getParent();
+while (Parent &&
+   (Parent->isAnonymousStructOrUnion() ||
+(Parent->isUnion() && Parent->getIdentifier() == nullptr))) {
+  if (auto RD = dyn_cast_or_null(Parent->getParent())) {
+Parent = RD;
+  } else {
+break;
+  }
+}
+
+auto ParentDecl = dyn_cast(Parent);
+if (!ParentDecl->isBeingDefined()) {
+  Sema::SpecialMemberOverloadResult SMOR = S.LookupSpecialMember(
+  ParentDecl, CXXSpecialMemberKind::DefaultConstructor, false, false,
+  false, false, false);
+  if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::Success) {

brevzin wrote:

I'm guessing this is the _wrong_ way to do this, but I don't know how to do it 
better. 

Also this doesn't exactly implement the wording I quoted above because the 
wording is just wrong (see future CWG issue 
[here](https://github.com/cplusplus/cwg/issues/722)).

https://github.com/llvm/llvm-project/pull/146815
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Partial implementation of support for P3074 (trivial unions) (PR #146815)

2025-07-09 Thread Barry Revzin via cfe-commits


@@ -0,0 +1,69 @@
+// RUN: %clang_cc1 -verify -std=c++26 %s -Wno-defaulted-function-deleted 
-triple x86_64-linux-gnu
+
+struct NonTrivial {

brevzin wrote:

Done.

https://github.com/llvm/llvm-project/pull/146815
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Partial implementation of support for P3074 (trivial unions) (PR #146815)

2025-07-09 Thread Barry Revzin via cfe-commits

https://github.com/brevzin updated 
https://github.com/llvm/llvm-project/pull/146815

>From 40290a957b6f349a9b670193c8bc699d8eb7d373 Mon Sep 17 00:00:00 2001
From: Barry Revzin 
Date: Fri, 27 Jun 2025 17:29:45 -0500
Subject: [PATCH 01/10] [P3074] Implementing part of trivial unions

---
 clang/lib/AST/DeclCXX.cpp   |  9 --
 clang/lib/Sema/SemaDeclCXX.cpp  | 16 +-
 clang/test/CXX/drs/cwg6xx.cpp   |  4 +--
 clang/test/CXX/special/class.ctor/p5-0x.cpp | 15 +-
 clang/test/CXX/special/class.ctor/p6-0x.cpp | 28 +
 clang/test/CXX/special/class.dtor/p5-0x.cpp | 33 +++--
 6 files changed, 63 insertions(+), 42 deletions(-)

diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index ccb308e103253..49adbdf1c393d 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1217,6 +1217,9 @@ void CXXRecordDecl::addedMember(Decl *D) {
 // those because they are always unnamed.
 bool IsZeroSize = Field->isZeroSize(Context);
 
+// P3074
+const bool TrivialUnion = Context.getLangOpts().CPlusPlus26 && isUnion();
+
 if (const auto *RecordTy = T->getAs()) {
   auto *FieldRec = cast(RecordTy->getDecl());
   if (FieldRec->getDefinition()) {
@@ -1277,7 +1280,7 @@ 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())
+if (!FieldRec->hasTrivialDefaultConstructor() && !TrivialUnion)
   data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor;
 
 // C++0x [class.copy]p13:
@@ -1315,9 +1318,9 @@ void CXXRecordDecl::addedMember(Decl *D) {
 if (!FieldRec->hasTrivialMoveAssignment())
   data().HasTrivialSpecialMembers &= ~SMF_MoveAssignment;
 
-if (!FieldRec->hasTrivialDestructor())
+if (!FieldRec->hasTrivialDestructor() && !TrivialUnion)
   data().HasTrivialSpecialMembers &= ~SMF_Destructor;
-if (!FieldRec->hasTrivialDestructorForCall())
+if (!FieldRec->hasTrivialDestructorForCall() && !TrivialUnion)
   data().HasTrivialSpecialMembersForCall &= ~SMF_Destructor;
 if (!FieldRec->hasIrrelevantDestructor())
   data().HasIrrelevantDestructor = false;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index e8c65025bfe6d..225409a69df53 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -9511,6 +9511,15 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
   CXXMethodDecl *Decl = SMOR.getMethod();
   FieldDecl *Field = Subobj.dyn_cast();
 
+  // P3074: default ctor and dtor for unions are not deleted, regardless of
+  // whether the underlying fields have non-trivial or deleted versions of 
those
+  // members
+  if (S.Context.getLangOpts().CPlusPlus26)
+if (Field && Field->getParent()->isUnion() &&
+(CSM == CXXSpecialMemberKind::DefaultConstructor ||
+ CSM == CXXSpecialMemberKind::Destructor))
+  return false;
+
   int DiagKind = -1;
 
   if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted)
@@ -9774,7 +9783,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.Context.getLangOpts().CPlusPlus26) {
 if (Diagnose)
   S.Diag(FieldRecord->getLocation(),
  diag::note_deleted_default_ctor_all_const)
@@ -9804,6 +9814,10 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForAllConstMembers() {
   // default constructor. Don't do that.
   if (CSM == CXXSpecialMemberKind::DefaultConstructor && inUnion() &&
   AllFieldsAreConst) {
+
+if (S.Context.getLangOpts().CPlusPlus26)
+  return false;
+
 bool AnyFields = false;
 for (auto *F : MD->getParent()->fields())
   if ((AnyFields = !F->isUnnamedBitField()))
diff --git a/clang/test/CXX/drs/cwg6xx.cpp b/clang/test/CXX/drs/cwg6xx.cpp
index e2eb009508b52..dd54bb5295b56 100644
--- a/clang/test/CXX/drs/cwg6xx.cpp
+++ b/clang/test/CXX/drs/cwg6xx.cpp
@@ -4,7 +4,7 @@
 // RUN: %clang_cc1 -std=c++17 %s 
-verify=expected,cxx11-20,cxx98-17,cxx11-17,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
 // RUN: %clang_cc1 -std=c++20 %s -verify=expected,cxx11-20,since-cxx11 
-fexceptions -fcxx-exceptions -pedantic-errors
 // RUN: %clang_cc1 -std=c++23 %s -verify=expected,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++2c %s -verify=expected,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
+// RUN: %clang_

[clang] [P3074] Partial implementation of support for trivial unions (PR #146815)

2025-07-03 Thread Barry Revzin via cfe-commits

https://github.com/brevzin updated 
https://github.com/llvm/llvm-project/pull/146815

>From 40290a957b6f349a9b670193c8bc699d8eb7d373 Mon Sep 17 00:00:00 2001
From: Barry Revzin 
Date: Fri, 27 Jun 2025 17:29:45 -0500
Subject: [PATCH 1/6] [P3074] Implementing part of trivial unions

---
 clang/lib/AST/DeclCXX.cpp   |  9 --
 clang/lib/Sema/SemaDeclCXX.cpp  | 16 +-
 clang/test/CXX/drs/cwg6xx.cpp   |  4 +--
 clang/test/CXX/special/class.ctor/p5-0x.cpp | 15 +-
 clang/test/CXX/special/class.ctor/p6-0x.cpp | 28 +
 clang/test/CXX/special/class.dtor/p5-0x.cpp | 33 +++--
 6 files changed, 63 insertions(+), 42 deletions(-)

diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index ccb308e103253..49adbdf1c393d 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1217,6 +1217,9 @@ void CXXRecordDecl::addedMember(Decl *D) {
 // those because they are always unnamed.
 bool IsZeroSize = Field->isZeroSize(Context);
 
+// P3074
+const bool TrivialUnion = Context.getLangOpts().CPlusPlus26 && isUnion();
+
 if (const auto *RecordTy = T->getAs()) {
   auto *FieldRec = cast(RecordTy->getDecl());
   if (FieldRec->getDefinition()) {
@@ -1277,7 +1280,7 @@ 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())
+if (!FieldRec->hasTrivialDefaultConstructor() && !TrivialUnion)
   data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor;
 
 // C++0x [class.copy]p13:
@@ -1315,9 +1318,9 @@ void CXXRecordDecl::addedMember(Decl *D) {
 if (!FieldRec->hasTrivialMoveAssignment())
   data().HasTrivialSpecialMembers &= ~SMF_MoveAssignment;
 
-if (!FieldRec->hasTrivialDestructor())
+if (!FieldRec->hasTrivialDestructor() && !TrivialUnion)
   data().HasTrivialSpecialMembers &= ~SMF_Destructor;
-if (!FieldRec->hasTrivialDestructorForCall())
+if (!FieldRec->hasTrivialDestructorForCall() && !TrivialUnion)
   data().HasTrivialSpecialMembersForCall &= ~SMF_Destructor;
 if (!FieldRec->hasIrrelevantDestructor())
   data().HasIrrelevantDestructor = false;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index e8c65025bfe6d..225409a69df53 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -9511,6 +9511,15 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
   CXXMethodDecl *Decl = SMOR.getMethod();
   FieldDecl *Field = Subobj.dyn_cast();
 
+  // P3074: default ctor and dtor for unions are not deleted, regardless of
+  // whether the underlying fields have non-trivial or deleted versions of 
those
+  // members
+  if (S.Context.getLangOpts().CPlusPlus26)
+if (Field && Field->getParent()->isUnion() &&
+(CSM == CXXSpecialMemberKind::DefaultConstructor ||
+ CSM == CXXSpecialMemberKind::Destructor))
+  return false;
+
   int DiagKind = -1;
 
   if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted)
@@ -9774,7 +9783,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.Context.getLangOpts().CPlusPlus26) {
 if (Diagnose)
   S.Diag(FieldRecord->getLocation(),
  diag::note_deleted_default_ctor_all_const)
@@ -9804,6 +9814,10 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForAllConstMembers() {
   // default constructor. Don't do that.
   if (CSM == CXXSpecialMemberKind::DefaultConstructor && inUnion() &&
   AllFieldsAreConst) {
+
+if (S.Context.getLangOpts().CPlusPlus26)
+  return false;
+
 bool AnyFields = false;
 for (auto *F : MD->getParent()->fields())
   if ((AnyFields = !F->isUnnamedBitField()))
diff --git a/clang/test/CXX/drs/cwg6xx.cpp b/clang/test/CXX/drs/cwg6xx.cpp
index e2eb009508b52..dd54bb5295b56 100644
--- a/clang/test/CXX/drs/cwg6xx.cpp
+++ b/clang/test/CXX/drs/cwg6xx.cpp
@@ -4,7 +4,7 @@
 // RUN: %clang_cc1 -std=c++17 %s 
-verify=expected,cxx11-20,cxx98-17,cxx11-17,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
 // RUN: %clang_cc1 -std=c++20 %s -verify=expected,cxx11-20,since-cxx11 
-fexceptions -fcxx-exceptions -pedantic-errors
 // RUN: %clang_cc1 -std=c++23 %s -verify=expected,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++2c %s -verify=expected,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc

[clang] [P3074] Partial implementation of support for trivial unions (PR #146815)

2025-07-03 Thread Barry Revzin via cfe-commits

https://github.com/brevzin updated 
https://github.com/llvm/llvm-project/pull/146815

>From 40290a957b6f349a9b670193c8bc699d8eb7d373 Mon Sep 17 00:00:00 2001
From: Barry Revzin 
Date: Fri, 27 Jun 2025 17:29:45 -0500
Subject: [PATCH 1/7] [P3074] Implementing part of trivial unions

---
 clang/lib/AST/DeclCXX.cpp   |  9 --
 clang/lib/Sema/SemaDeclCXX.cpp  | 16 +-
 clang/test/CXX/drs/cwg6xx.cpp   |  4 +--
 clang/test/CXX/special/class.ctor/p5-0x.cpp | 15 +-
 clang/test/CXX/special/class.ctor/p6-0x.cpp | 28 +
 clang/test/CXX/special/class.dtor/p5-0x.cpp | 33 +++--
 6 files changed, 63 insertions(+), 42 deletions(-)

diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index ccb308e103253..49adbdf1c393d 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1217,6 +1217,9 @@ void CXXRecordDecl::addedMember(Decl *D) {
 // those because they are always unnamed.
 bool IsZeroSize = Field->isZeroSize(Context);
 
+// P3074
+const bool TrivialUnion = Context.getLangOpts().CPlusPlus26 && isUnion();
+
 if (const auto *RecordTy = T->getAs()) {
   auto *FieldRec = cast(RecordTy->getDecl());
   if (FieldRec->getDefinition()) {
@@ -1277,7 +1280,7 @@ 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())
+if (!FieldRec->hasTrivialDefaultConstructor() && !TrivialUnion)
   data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor;
 
 // C++0x [class.copy]p13:
@@ -1315,9 +1318,9 @@ void CXXRecordDecl::addedMember(Decl *D) {
 if (!FieldRec->hasTrivialMoveAssignment())
   data().HasTrivialSpecialMembers &= ~SMF_MoveAssignment;
 
-if (!FieldRec->hasTrivialDestructor())
+if (!FieldRec->hasTrivialDestructor() && !TrivialUnion)
   data().HasTrivialSpecialMembers &= ~SMF_Destructor;
-if (!FieldRec->hasTrivialDestructorForCall())
+if (!FieldRec->hasTrivialDestructorForCall() && !TrivialUnion)
   data().HasTrivialSpecialMembersForCall &= ~SMF_Destructor;
 if (!FieldRec->hasIrrelevantDestructor())
   data().HasIrrelevantDestructor = false;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index e8c65025bfe6d..225409a69df53 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -9511,6 +9511,15 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
   CXXMethodDecl *Decl = SMOR.getMethod();
   FieldDecl *Field = Subobj.dyn_cast();
 
+  // P3074: default ctor and dtor for unions are not deleted, regardless of
+  // whether the underlying fields have non-trivial or deleted versions of 
those
+  // members
+  if (S.Context.getLangOpts().CPlusPlus26)
+if (Field && Field->getParent()->isUnion() &&
+(CSM == CXXSpecialMemberKind::DefaultConstructor ||
+ CSM == CXXSpecialMemberKind::Destructor))
+  return false;
+
   int DiagKind = -1;
 
   if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted)
@@ -9774,7 +9783,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.Context.getLangOpts().CPlusPlus26) {
 if (Diagnose)
   S.Diag(FieldRecord->getLocation(),
  diag::note_deleted_default_ctor_all_const)
@@ -9804,6 +9814,10 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForAllConstMembers() {
   // default constructor. Don't do that.
   if (CSM == CXXSpecialMemberKind::DefaultConstructor && inUnion() &&
   AllFieldsAreConst) {
+
+if (S.Context.getLangOpts().CPlusPlus26)
+  return false;
+
 bool AnyFields = false;
 for (auto *F : MD->getParent()->fields())
   if ((AnyFields = !F->isUnnamedBitField()))
diff --git a/clang/test/CXX/drs/cwg6xx.cpp b/clang/test/CXX/drs/cwg6xx.cpp
index e2eb009508b52..dd54bb5295b56 100644
--- a/clang/test/CXX/drs/cwg6xx.cpp
+++ b/clang/test/CXX/drs/cwg6xx.cpp
@@ -4,7 +4,7 @@
 // RUN: %clang_cc1 -std=c++17 %s 
-verify=expected,cxx11-20,cxx98-17,cxx11-17,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
 // RUN: %clang_cc1 -std=c++20 %s -verify=expected,cxx11-20,since-cxx11 
-fexceptions -fcxx-exceptions -pedantic-errors
 // RUN: %clang_cc1 -std=c++23 %s -verify=expected,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++2c %s -verify=expected,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc

[clang] [P3074] Partial implementation of support for trivial unions (PR #146815)

2025-07-03 Thread Barry Revzin via cfe-commits

https://github.com/brevzin updated 
https://github.com/llvm/llvm-project/pull/146815

>From 40290a957b6f349a9b670193c8bc699d8eb7d373 Mon Sep 17 00:00:00 2001
From: Barry Revzin 
Date: Fri, 27 Jun 2025 17:29:45 -0500
Subject: [PATCH 1/5] [P3074] Implementing part of trivial unions

---
 clang/lib/AST/DeclCXX.cpp   |  9 --
 clang/lib/Sema/SemaDeclCXX.cpp  | 16 +-
 clang/test/CXX/drs/cwg6xx.cpp   |  4 +--
 clang/test/CXX/special/class.ctor/p5-0x.cpp | 15 +-
 clang/test/CXX/special/class.ctor/p6-0x.cpp | 28 +
 clang/test/CXX/special/class.dtor/p5-0x.cpp | 33 +++--
 6 files changed, 63 insertions(+), 42 deletions(-)

diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index ccb308e103253..49adbdf1c393d 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1217,6 +1217,9 @@ void CXXRecordDecl::addedMember(Decl *D) {
 // those because they are always unnamed.
 bool IsZeroSize = Field->isZeroSize(Context);
 
+// P3074
+const bool TrivialUnion = Context.getLangOpts().CPlusPlus26 && isUnion();
+
 if (const auto *RecordTy = T->getAs()) {
   auto *FieldRec = cast(RecordTy->getDecl());
   if (FieldRec->getDefinition()) {
@@ -1277,7 +1280,7 @@ 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())
+if (!FieldRec->hasTrivialDefaultConstructor() && !TrivialUnion)
   data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor;
 
 // C++0x [class.copy]p13:
@@ -1315,9 +1318,9 @@ void CXXRecordDecl::addedMember(Decl *D) {
 if (!FieldRec->hasTrivialMoveAssignment())
   data().HasTrivialSpecialMembers &= ~SMF_MoveAssignment;
 
-if (!FieldRec->hasTrivialDestructor())
+if (!FieldRec->hasTrivialDestructor() && !TrivialUnion)
   data().HasTrivialSpecialMembers &= ~SMF_Destructor;
-if (!FieldRec->hasTrivialDestructorForCall())
+if (!FieldRec->hasTrivialDestructorForCall() && !TrivialUnion)
   data().HasTrivialSpecialMembersForCall &= ~SMF_Destructor;
 if (!FieldRec->hasIrrelevantDestructor())
   data().HasIrrelevantDestructor = false;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index e8c65025bfe6d..225409a69df53 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -9511,6 +9511,15 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
   CXXMethodDecl *Decl = SMOR.getMethod();
   FieldDecl *Field = Subobj.dyn_cast();
 
+  // P3074: default ctor and dtor for unions are not deleted, regardless of
+  // whether the underlying fields have non-trivial or deleted versions of 
those
+  // members
+  if (S.Context.getLangOpts().CPlusPlus26)
+if (Field && Field->getParent()->isUnion() &&
+(CSM == CXXSpecialMemberKind::DefaultConstructor ||
+ CSM == CXXSpecialMemberKind::Destructor))
+  return false;
+
   int DiagKind = -1;
 
   if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted)
@@ -9774,7 +9783,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.Context.getLangOpts().CPlusPlus26) {
 if (Diagnose)
   S.Diag(FieldRecord->getLocation(),
  diag::note_deleted_default_ctor_all_const)
@@ -9804,6 +9814,10 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForAllConstMembers() {
   // default constructor. Don't do that.
   if (CSM == CXXSpecialMemberKind::DefaultConstructor && inUnion() &&
   AllFieldsAreConst) {
+
+if (S.Context.getLangOpts().CPlusPlus26)
+  return false;
+
 bool AnyFields = false;
 for (auto *F : MD->getParent()->fields())
   if ((AnyFields = !F->isUnnamedBitField()))
diff --git a/clang/test/CXX/drs/cwg6xx.cpp b/clang/test/CXX/drs/cwg6xx.cpp
index e2eb009508b52..dd54bb5295b56 100644
--- a/clang/test/CXX/drs/cwg6xx.cpp
+++ b/clang/test/CXX/drs/cwg6xx.cpp
@@ -4,7 +4,7 @@
 // RUN: %clang_cc1 -std=c++17 %s 
-verify=expected,cxx11-20,cxx98-17,cxx11-17,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
 // RUN: %clang_cc1 -std=c++20 %s -verify=expected,cxx11-20,since-cxx11 
-fexceptions -fcxx-exceptions -pedantic-errors
 // RUN: %clang_cc1 -std=c++23 %s -verify=expected,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++2c %s -verify=expected,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc

[clang] [P3074] Partial implementation of support for trivial unions (PR #146815)

2025-07-03 Thread Barry Revzin via cfe-commits


@@ -922,7 +922,7 @@ namespace cwg667 { // cwg667: 8
 
   struct B { ~B() = delete; };
   union C { B b; };
-  static_assert(!__is_trivially_destructible(C), "");
+  static_assert(!__is_trivially_destructible(C), ""); // cxx26-error {{failed}}

brevzin wrote:

Done.

https://github.com/llvm/llvm-project/pull/146815
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [P3074] Partial implementation of support for trivial unions (PR #146815)

2025-07-03 Thread Barry Revzin via cfe-commits


@@ -23,8 +24,8 @@ int n;
 
 // - X is a union-like class that has a variant member with a non-trivial
 // default constructor,
-union Deleted1a { UserProvidedDefCtor u; }; // expected-note {{default 
constructor of 'Deleted1a' is implicitly deleted because variant field 'u' has 
a non-trivial default constructor}}
-Deleted1a d1a; // expected-error {{implicitly-deleted default constructor}}
+union Deleted1a { UserProvidedDefCtor u; }; // until26-note {{default 
constructor of 'Deleted1a' is implicitly deleted because variant field 'u' has 
a non-trivial default constructor}}
+Deleted1a d1a; // until26-error {{implicitly-deleted default constructor}}

brevzin wrote:

Done. I just added the C++23 line too, since the test starts at C++11. 

https://github.com/llvm/llvm-project/pull/146815
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [P3074] Parital implementation of support for trivial unions (PR #146815)

2025-07-02 Thread Barry Revzin via cfe-commits

https://github.com/brevzin created 
https://github.com/llvm/llvm-project/pull/146815

This commit makes union construction/destruction trivial by default, but does 
not add the lifetime aspects of the paper — am holding out until P3726R0 will 
be discussed which alters that approach somewhat based on feedback from Richard 
Smith. But the constructor/destructor part is common regardless and also 
simpler.

>From d070148afae5aa5e325b34c02e2d0ffb67325d7e Mon Sep 17 00:00:00 2001
From: Barry Revzin 
Date: Fri, 27 Jun 2025 17:29:45 -0500
Subject: [PATCH] [P3074] Implementing part of trivial unions

---
 clang/lib/AST/DeclCXX.cpp   |  9 --
 clang/lib/Sema/SemaDeclCXX.cpp  | 16 +-
 clang/test/CXX/drs/cwg6xx.cpp   |  4 +--
 clang/test/CXX/special/class.ctor/p5-0x.cpp | 15 +-
 clang/test/CXX/special/class.ctor/p6-0x.cpp | 28 +
 clang/test/CXX/special/class.dtor/p5-0x.cpp | 33 +++--
 6 files changed, 63 insertions(+), 42 deletions(-)

diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index ccb308e103253..49adbdf1c393d 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1217,6 +1217,9 @@ void CXXRecordDecl::addedMember(Decl *D) {
 // those because they are always unnamed.
 bool IsZeroSize = Field->isZeroSize(Context);
 
+// P3074
+const bool TrivialUnion = Context.getLangOpts().CPlusPlus26 && isUnion();
+
 if (const auto *RecordTy = T->getAs()) {
   auto *FieldRec = cast(RecordTy->getDecl());
   if (FieldRec->getDefinition()) {
@@ -1277,7 +1280,7 @@ 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())
+if (!FieldRec->hasTrivialDefaultConstructor() && !TrivialUnion)
   data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor;
 
 // C++0x [class.copy]p13:
@@ -1315,9 +1318,9 @@ void CXXRecordDecl::addedMember(Decl *D) {
 if (!FieldRec->hasTrivialMoveAssignment())
   data().HasTrivialSpecialMembers &= ~SMF_MoveAssignment;
 
-if (!FieldRec->hasTrivialDestructor())
+if (!FieldRec->hasTrivialDestructor() && !TrivialUnion)
   data().HasTrivialSpecialMembers &= ~SMF_Destructor;
-if (!FieldRec->hasTrivialDestructorForCall())
+if (!FieldRec->hasTrivialDestructorForCall() && !TrivialUnion)
   data().HasTrivialSpecialMembersForCall &= ~SMF_Destructor;
 if (!FieldRec->hasIrrelevantDestructor())
   data().HasIrrelevantDestructor = false;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index e8c65025bfe6d..e9b45bf99620c 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -9511,6 +9511,15 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
   CXXMethodDecl *Decl = SMOR.getMethod();
   FieldDecl *Field = Subobj.dyn_cast();
 
+  // P3074: default ctor and dtor for unions are not deleted, regardless of
+  // whether the underlying fields have non-trivial or deleted versions of 
those
+  // members
+  if (S.Context.getLangOpts().CPlusPlus26)
+if (Field && Field->getParent()->isUnion() &&
+(CSM == CXXSpecialMemberKind::DefaultConstructor ||
+ CSM == CXXSpecialMemberKind::Destructor))
+  return false;
+
   int DiagKind = -1;
 
   if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted)
@@ -9774,7 +9783,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() &&
+  !this->S.Context.getLangOpts().CPlusPlus26) {
 if (Diagnose)
   S.Diag(FieldRecord->getLocation(),
  diag::note_deleted_default_ctor_all_const)
@@ -9804,6 +9814,10 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForAllConstMembers() {
   // default constructor. Don't do that.
   if (CSM == CXXSpecialMemberKind::DefaultConstructor && inUnion() &&
   AllFieldsAreConst) {
+
+if (S.Context.getLangOpts().CPlusPlus26)
+  return false;
+
 bool AnyFields = false;
 for (auto *F : MD->getParent()->fields())
   if ((AnyFields = !F->isUnnamedBitField()))
diff --git a/clang/test/CXX/drs/cwg6xx.cpp b/clang/test/CXX/drs/cwg6xx.cpp
index e2eb009508b52..dd54bb5295b56 100644
--- a/clang/test/CXX/drs/cwg6xx.cpp
+++ b/clang/test/CXX/drs/cwg6xx.cpp
@@ -4,7 +4,7 @@
 // RUN: %clang_cc1 -std=c++17 %s 
-verify=expected,cxx11-20,cxx98-17,cxx11-17,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
 // RUN: %clang_cc1 -std=c++20 %s -

[clang] [P3074] Partial implementation of support for trivial unions (PR #146815)

2025-07-02 Thread Barry Revzin via cfe-commits

https://github.com/brevzin edited 
https://github.com/llvm/llvm-project/pull/146815
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [P3074] Partial implementation of support for trivial unions (PR #146815)

2025-07-02 Thread Barry Revzin via cfe-commits

brevzin wrote:

Oh. Actually I didn't quite properly implement the destructor rule, since that 
changed since I originally implemented this. The new rule is that the default 
destructor for a union `X` [is deleted 
if](http://eel.is/c++draft/class.dtor#7.2)

* default constructing an `X` either fails, or is deleted, or is non trivial, or
* one of the members `M` of `X` has a default member initializer and `M`'s 
destructor is non-trivial.

I don't know how to do that yet, so plz don't merge (although I suspect there 
are other changes to be made).

https://github.com/llvm/llvm-project/pull/146815
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [P3074] Partial implementation of support for trivial unions (PR #146815)

2025-07-02 Thread Barry Revzin via cfe-commits

https://github.com/brevzin updated 
https://github.com/llvm/llvm-project/pull/146815

>From 40290a957b6f349a9b670193c8bc699d8eb7d373 Mon Sep 17 00:00:00 2001
From: Barry Revzin 
Date: Fri, 27 Jun 2025 17:29:45 -0500
Subject: [PATCH 1/2] [P3074] Implementing part of trivial unions

---
 clang/lib/AST/DeclCXX.cpp   |  9 --
 clang/lib/Sema/SemaDeclCXX.cpp  | 16 +-
 clang/test/CXX/drs/cwg6xx.cpp   |  4 +--
 clang/test/CXX/special/class.ctor/p5-0x.cpp | 15 +-
 clang/test/CXX/special/class.ctor/p6-0x.cpp | 28 +
 clang/test/CXX/special/class.dtor/p5-0x.cpp | 33 +++--
 6 files changed, 63 insertions(+), 42 deletions(-)

diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index ccb308e103253..49adbdf1c393d 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1217,6 +1217,9 @@ void CXXRecordDecl::addedMember(Decl *D) {
 // those because they are always unnamed.
 bool IsZeroSize = Field->isZeroSize(Context);
 
+// P3074
+const bool TrivialUnion = Context.getLangOpts().CPlusPlus26 && isUnion();
+
 if (const auto *RecordTy = T->getAs()) {
   auto *FieldRec = cast(RecordTy->getDecl());
   if (FieldRec->getDefinition()) {
@@ -1277,7 +1280,7 @@ 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())
+if (!FieldRec->hasTrivialDefaultConstructor() && !TrivialUnion)
   data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor;
 
 // C++0x [class.copy]p13:
@@ -1315,9 +1318,9 @@ void CXXRecordDecl::addedMember(Decl *D) {
 if (!FieldRec->hasTrivialMoveAssignment())
   data().HasTrivialSpecialMembers &= ~SMF_MoveAssignment;
 
-if (!FieldRec->hasTrivialDestructor())
+if (!FieldRec->hasTrivialDestructor() && !TrivialUnion)
   data().HasTrivialSpecialMembers &= ~SMF_Destructor;
-if (!FieldRec->hasTrivialDestructorForCall())
+if (!FieldRec->hasTrivialDestructorForCall() && !TrivialUnion)
   data().HasTrivialSpecialMembersForCall &= ~SMF_Destructor;
 if (!FieldRec->hasIrrelevantDestructor())
   data().HasIrrelevantDestructor = false;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index e8c65025bfe6d..225409a69df53 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -9511,6 +9511,15 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
   CXXMethodDecl *Decl = SMOR.getMethod();
   FieldDecl *Field = Subobj.dyn_cast();
 
+  // P3074: default ctor and dtor for unions are not deleted, regardless of
+  // whether the underlying fields have non-trivial or deleted versions of 
those
+  // members
+  if (S.Context.getLangOpts().CPlusPlus26)
+if (Field && Field->getParent()->isUnion() &&
+(CSM == CXXSpecialMemberKind::DefaultConstructor ||
+ CSM == CXXSpecialMemberKind::Destructor))
+  return false;
+
   int DiagKind = -1;
 
   if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted)
@@ -9774,7 +9783,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.Context.getLangOpts().CPlusPlus26) {
 if (Diagnose)
   S.Diag(FieldRecord->getLocation(),
  diag::note_deleted_default_ctor_all_const)
@@ -9804,6 +9814,10 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForAllConstMembers() {
   // default constructor. Don't do that.
   if (CSM == CXXSpecialMemberKind::DefaultConstructor && inUnion() &&
   AllFieldsAreConst) {
+
+if (S.Context.getLangOpts().CPlusPlus26)
+  return false;
+
 bool AnyFields = false;
 for (auto *F : MD->getParent()->fields())
   if ((AnyFields = !F->isUnnamedBitField()))
diff --git a/clang/test/CXX/drs/cwg6xx.cpp b/clang/test/CXX/drs/cwg6xx.cpp
index e2eb009508b52..dd54bb5295b56 100644
--- a/clang/test/CXX/drs/cwg6xx.cpp
+++ b/clang/test/CXX/drs/cwg6xx.cpp
@@ -4,7 +4,7 @@
 // RUN: %clang_cc1 -std=c++17 %s 
-verify=expected,cxx11-20,cxx98-17,cxx11-17,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
 // RUN: %clang_cc1 -std=c++20 %s -verify=expected,cxx11-20,since-cxx11 
-fexceptions -fcxx-exceptions -pedantic-errors
 // RUN: %clang_cc1 -std=c++23 %s -verify=expected,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++2c %s -verify=expected,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc