https://github.com/egorshamshura updated 
https://github.com/llvm/llvm-project/pull/142341

>From 2e423a75e5ee8b5ecc450d4457fc677fd0c08ad2 Mon Sep 17 00:00:00 2001
From: Shamshura Egor <shamshurae...@gmail.com>
Date: Mon, 2 Jun 2025 07:25:26 +0000
Subject: [PATCH 1/7] [Clang] Added explanation why a is trivial copyable
 evaluated to false.

---
 .../clang/Basic/DiagnosticSemaKinds.td        |  5 +-
 clang/lib/Sema/SemaTypeTraits.cpp             | 97 +++++++++++++++++++
 .../type-traits-unsatisfied-diags-std.cpp     | 72 ++++++++++++++
 .../SemaCXX/type-traits-unsatisfied-diags.cpp | 80 +++++++++++++++
 4 files changed, 253 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index efc842bb4c42e..748e0720c5ef5 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1764,7 +1764,8 @@ def err_user_defined_msg_constexpr : Error<
 
 // Type traits explanations
 def note_unsatisfied_trait : Note<"%0 is not %enum_select<TraitName>{"
-                                  "%TriviallyRelocatable{trivially 
relocatable}"
+                                  "%TriviallyRelocatable{trivially 
relocatable}|"
+                                  "%TriviallyCopyable{trivially copyable}"
                                   "}1">;
 
 def note_unsatisfied_trait_reason
@@ -1776,6 +1777,8 @@ def note_unsatisfied_trait_reason
            "%VBase{has a virtual base %1}|"
            "%NRBase{has a non-trivially-relocatable base %1}|"
            "%NRField{has a non-trivially-relocatable member %1 of type %2}|"
+           "%NTCBase{has a non-trivially-copyable base %1}|"
+           "%NTCField{has a non-trivially-copyable member %1 of type %2}|"
            "%DeletedDtr{has a %select{deleted|user-provided}1 destructor}|"
            "%UserProvidedCtr{has a user provided %select{copy|move}1 "
            "constructor}|"
diff --git a/clang/lib/Sema/SemaTypeTraits.cpp 
b/clang/lib/Sema/SemaTypeTraits.cpp
index 7bf3c8eaabf4b..aaa5aff53fbc5 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -11,8 +11,10 @@
 
//===----------------------------------------------------------------------===//
 
 #include "clang/AST/DeclCXX.h"
+#include "clang/AST/Type.h"
 #include "clang/Basic/DiagnosticParse.h"
 #include "clang/Basic/DiagnosticSema.h"
+#include "clang/Basic/TypeTraits.h"
 #include "clang/Sema/EnterExpressionEvaluationContext.h"
 #include "clang/Sema/Initialization.h"
 #include "clang/Sema/Lookup.h"
@@ -1922,6 +1924,7 @@ static std::optional<TypeTrait> 
StdNameToTypeTrait(StringRef Name) {
   return llvm::StringSwitch<std::optional<TypeTrait>>(Name)
       .Case("is_trivially_relocatable",
             TypeTrait::UTT_IsCppTriviallyRelocatable)
+      .Case("is_trivially_copyable", TypeTrait::UTT_IsTriviallyCopyable)
       .Default(std::nullopt);
 }
 
@@ -2083,6 +2086,97 @@ static void DiagnoseNonTriviallyRelocatableReason(Sema 
&SemaRef,
   SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D;
 }
 
+static void DiagnoseNonTriviallyCopyableReason(Sema &SemaRef,
+                                               SourceLocation Loc,
+                                               const CXXRecordDecl *D) {
+  for (const CXXBaseSpecifier &B : D->bases()) {
+    assert(B.getType()->getAsCXXRecordDecl() && "invalid base?");
+    if (B.isVirtual())
+      SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+          << diag::TraitNotSatisfiedReason::VBase << B.getType()
+          << B.getSourceRange();
+    if (!B.getType().isTriviallyCopyableType(D->getASTContext())) {
+      SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+          << diag::TraitNotSatisfiedReason::NTCBase << B.getType()
+          << B.getSourceRange();
+    }
+  }
+  for (const FieldDecl *Field : D->fields()) {
+    if (!Field->getType().isTriviallyCopyableType(Field->getASTContext()))
+      SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+          << diag::TraitNotSatisfiedReason::NTCField << Field
+          << Field->getType() << Field->getSourceRange();
+  }
+  if (D->hasDeletedDestructor())
+    SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+        << diag::TraitNotSatisfiedReason::DeletedDtr << 0
+        << D->getDestructor()->getSourceRange();
+
+  if (D->isUnion()) {
+    auto DiagSPM = [&](CXXSpecialMemberKind K, bool Has) {
+      if (Has)
+        SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+            << diag::TraitNotSatisfiedReason::UnionWithUserDeclaredSMF << K;
+    };
+    DiagSPM(CXXSpecialMemberKind::CopyConstructor,
+            D->hasUserDeclaredCopyConstructor());
+    DiagSPM(CXXSpecialMemberKind::CopyAssignment,
+            D->hasUserDeclaredCopyAssignment());
+    DiagSPM(CXXSpecialMemberKind::MoveConstructor,
+            D->hasUserDeclaredMoveConstructor());
+    DiagSPM(CXXSpecialMemberKind::MoveAssignment,
+            D->hasUserDeclaredMoveAssignment());
+    return;
+  }
+
+  if (!D->hasSimpleMoveConstructor() && !D->hasSimpleCopyConstructor()) {
+    const auto *Decl = cast<CXXConstructorDecl>(
+        LookupSpecialMemberFromXValue(SemaRef, D, /*Assign=*/false));
+    if (Decl && Decl->isUserProvided())
+      SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+          << diag::TraitNotSatisfiedReason::UserProvidedCtr
+          << Decl->isMoveConstructor() << Decl->getSourceRange();
+  }
+  if (!D->hasSimpleMoveAssignment() && !D->hasSimpleCopyAssignment()) {
+    CXXMethodDecl *Decl =
+        LookupSpecialMemberFromXValue(SemaRef, D, /*Assign=*/true);
+    if (Decl && Decl->isUserProvided())
+      SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+          << diag::TraitNotSatisfiedReason::UserProvidedAssign
+          << Decl->isMoveAssignmentOperator() << Decl->getSourceRange();
+  }
+  CXXDestructorDecl *Dtr = D->getDestructor();
+  if (Dtr && Dtr->isUserProvided() && !Dtr->isDefaulted())
+    SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+        << diag::TraitNotSatisfiedReason::DeletedDtr << 1
+        << Dtr->getSourceRange();
+}
+
+static void DiagnoseNonTriviallyCopyableReason(Sema &SemaRef,
+                                               SourceLocation Loc, QualType T) 
{
+  SemaRef.Diag(Loc, diag::note_unsatisfied_trait)
+      << T << diag::TraitName::TriviallyCopyable;
+
+  if (T->isReferenceType())
+    SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+        << diag::TraitNotSatisfiedReason::Ref;
+
+  T = T.getNonReferenceType();
+
+  if (T.hasNonTrivialObjCLifetime())
+    SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+        << diag::TraitNotSatisfiedReason::HasArcLifetime;
+
+  const CXXRecordDecl *D = T->getAsCXXRecordDecl();
+  if (!D || D->isInvalidDecl())
+    return;
+
+  if (D->hasDefinition())
+    DiagnoseNonTriviallyCopyableReason(SemaRef, Loc, D);
+
+  SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D;
+}
+
 void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
   E = E->IgnoreParenImpCasts();
   if (E->containsErrors())
@@ -2097,6 +2191,9 @@ void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
   case UTT_IsCppTriviallyRelocatable:
     DiagnoseNonTriviallyRelocatableReason(*this, E->getBeginLoc(), Args[0]);
     break;
+  case UTT_IsTriviallyCopyable:
+    DiagnoseNonTriviallyCopyableReason(*this, E->getBeginLoc(), Args[0]);
+    break;
   default:
     break;
   }
diff --git a/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp 
b/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
index 90cff1e66000c..498e202e26265 100644
--- a/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
+++ b/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
@@ -12,6 +12,14 @@ struct is_trivially_relocatable {
 
 template <typename T>
 constexpr bool is_trivially_relocatable_v = 
__builtin_is_cpp_trivially_relocatable(T);
+
+template <typename T>
+struct is_trivially_copyable {
+    static constexpr bool value = __is_trivially_copyable(T);
+};
+
+template <typename T>
+constexpr bool is_trivially_copyable_v = __is_trivially_copyable(T);
 #endif
 
 #ifdef STD2
@@ -25,6 +33,17 @@ using is_trivially_relocatable  = 
__details_is_trivially_relocatable<T>;
 
 template <typename T>
 constexpr bool is_trivially_relocatable_v = 
__builtin_is_cpp_trivially_relocatable(T);
+
+template <typename T>
+struct __details_is_trivially_copyable {
+    static constexpr bool value = __is_trivially_copyable(T);
+};
+
+template <typename T>
+using is_trivially_copyable  = __details_is_trivially_copyable<T>;
+
+template <typename T>
+constexpr bool is_trivially_copyable_v = __is_trivially_copyable(T);
 #endif
 
 
@@ -45,6 +64,15 @@ using is_trivially_relocatable  = 
__details_is_trivially_relocatable<T>;
 
 template <typename T>
 constexpr bool is_trivially_relocatable_v = is_trivially_relocatable<T>::value;
+
+template <typename T>
+struct __details_is_trivially_copyable : 
bool_constant<__is_trivially_copyable(T)> {};
+
+template <typename T>
+using is_trivially_copyable  = __details_is_trivially_copyable<T>;
+
+template <typename T>
+constexpr bool is_trivially_copyable_v = is_trivially_copyable<T>::value;
 #endif
 
 }
@@ -60,6 +88,18 @@ static_assert(std::is_trivially_relocatable_v<int&>);
 // expected-note@-1 {{'int &' is not trivially relocatable}} \
 // expected-note@-1 {{because it is a reference type}}
 
+static_assert(std::is_trivially_copyable<int>::value);
+
+static_assert(std::is_trivially_copyable<int&>::value);
+// expected-error-re@-1 {{static assertion failed due to requirement 
'std::{{.*}}is_trivially_copyable<int &>::value'}} \
+// expected-note@-1 {{'int &' is not trivially copyable}} \
+// expected-note@-1 {{because it is a reference type}}
+static_assert(std::is_trivially_copyable_v<int&>);
+// expected-error@-1 {{static assertion failed due to requirement 
'std::is_trivially_copyable_v<int &>'}} \
+// expected-note@-1 {{'int &' is not trivially copyable}} \
+// expected-note@-1 {{because it is a reference type}}
+
+
 namespace test_namespace {
     using namespace std;
     static_assert(is_trivially_relocatable<int&>::value);
@@ -70,6 +110,15 @@ namespace test_namespace {
     // expected-error@-1 {{static assertion failed due to requirement 
'is_trivially_relocatable_v<int &>'}} \
     // expected-note@-1 {{'int &' is not trivially relocatable}} \
     // expected-note@-1 {{because it is a reference type}}
+
+    static_assert(is_trivially_copyable<int&>::value);
+    // expected-error-re@-1 {{static assertion failed due to requirement 
'{{.*}}is_trivially_copyable<int &>::value'}} \
+    // expected-note@-1 {{'int &' is not trivially copyable}} \
+    // expected-note@-1 {{because it is a reference type}}
+    static_assert(is_trivially_copyable_v<int&>);
+    // expected-error@-1 {{static assertion failed due to requirement 
'is_trivially_copyable_v<int &>'}} \
+    // expected-note@-1 {{'int &' is not trivially copyable}} \
+    // expected-note@-1 {{because it is a reference type}}
 }
 
 
@@ -82,6 +131,14 @@ concept C = std::is_trivially_relocatable_v<T>; // #concept2
 
 template <C T> void g();  // #cand2
 
+template <typename T>
+requires std::is_trivially_copyable<T>::value void f2();  // #cand3
+
+template <typename T>
+concept C2 = std::is_trivially_copyable_v<T>; // #concept4
+
+template <C2 T> void g2();  // #cand4
+
 void test() {
     f<int&>();
     // expected-error@-1 {{no matching function for call to 'f'}} \
@@ -97,5 +154,20 @@ void test() {
     // expected-note@#concept2 {{because 'std::is_trivially_relocatable_v<int 
&>' evaluated to false}} \
     // expected-note@#concept2 {{'int &' is not trivially relocatable}} \
     // expected-note@#concept2 {{because it is a reference type}}
+
+    f2<int&>();
+    // expected-error@-1 {{no matching function for call to 'f2'}} \
+    // expected-note@#cand3 {{candidate template ignored: constraints not 
satisfied [with T = int &]}} \
+    // expected-note-re@#cand3 {{because '{{.*}}is_trivially_copyable<int 
&>::value' evaluated to false}} \
+    // expected-note@#cand3 {{'int &' is not trivially copyable}} \
+    // expected-note@#cand3 {{because it is a reference type}}
+
+    g2<int&>();
+    // expected-error@-1 {{no matching function for call to 'g2'}} \
+    // expected-note@#cand4 {{candidate template ignored: constraints not 
satisfied [with T = int &]}} \
+    // expected-note@#cand4 {{because 'int &' does not satisfy 'C2'}} \
+    // expected-note@#concept4 {{because 'std::is_trivially_copyable_v<int &>' 
evaluated to false}} \
+    // expected-note@#concept4 {{'int &' is not trivially copyable}} \
+    // expected-note@#concept4 {{because it is a reference type}}
 }
 }
diff --git a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp 
b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
index d9cab20f4febd..97510fe2eca9f 100644
--- a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
+++ b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
@@ -144,3 +144,83 @@ static_assert(__builtin_is_cpp_trivially_relocatable(U2));
 // expected-note@#tr-U2 {{'U2' defined here}}
 
 }
+
+namespace trivially_copyable {
+struct B {
+ virtual ~B();
+};
+struct S : virtual B { // #tc-S
+    S();
+    int & a;
+    const int ci;
+    B & b;
+    B c;
+    ~S();
+};
+static_assert(__is_trivially_copyable(S));
+// expected-error@-1 {{static assertion failed due to requirement 
'__is_trivially_copyable(trivially_copyable::S)'}} \
+// expected-note@-1 {{'S' is not trivially copyable}} \
+// expected-note@-1 {{because it has a virtual base 'B'}} \
+// expected-note@-1 {{because it has a non-trivially-copyable base 'B'}} \
+// expected-note@-1 {{because it has a non-trivially-copyable member 'c' of 
type 'B'}} \
+// expected-note@-1 {{because it has a non-trivially-copyable member 'b' of 
type 'B &'}} \
+// expected-note@-1 {{because it has a non-trivially-copyable member 'a' of 
type 'int &'}} \
+// expected-note@-1 {{because it has a user-provided destructor}}
+// expected-note@#tc-S {{'S' defined here}}
+
+struct S2 { // #tc-S2
+    S2(S2&&);
+    S2& operator=(const S2&);
+};
+static_assert(__is_trivially_copyable(S2));
+// expected-error@-1 {{static assertion failed due to requirement 
'__is_trivially_copyable(trivially_copyable::S2)'}} \
+// expected-note@-1 {{'S2' is not trivially copyable}} \
+// expected-note@-1 {{because it has a user provided move constructor}} \
+// expected-note@-1 {{because it has a user provided copy assignment 
operator}} \
+// expected-note@#tc-S2 {{'S2' defined here}}
+
+struct S3 {
+    ~S3() = delete;
+};
+static_assert(__is_trivially_copyable(S3));
+
+union U { // #tc-U
+    U(const U&);
+    U(U&&);
+    U& operator=(const U&);
+    U& operator=(U&&);
+};
+static_assert(__is_trivially_copyable(U));
+// expected-error@-1 {{static assertion failed due to requirement 
'__is_trivially_copyable(trivially_copyable::U)'}} \
+// expected-note@-1 {{'U' is not trivially copyable}} \
+// expected-note@-1 {{because it is a union with a user-declared copy 
constructor}} \
+// expected-note@-1 {{because it is a union with a user-declared copy 
assignment operator}} \
+// expected-note@-1 {{because it is a union with a user-declared move 
constructor}} \
+// expected-note@-1 {{because it is a union with a user-declared move 
assignment operator}}
+// expected-note@#tc-U {{'U' defined here}}
+
+struct S4 { // #tc-S4
+    ~S4();
+    B b;
+};
+static_assert(__is_trivially_copyable(S4));
+// expected-error@-1 {{static assertion failed due to requirement 
'__is_trivially_copyable(trivially_copyable::S4)'}} \
+// expected-note@-1 {{'S4' is not trivially copyable}} \
+// expected-note@-1 {{because it has a non-trivially-copyable member 'b' of 
type 'B'}} \
+// expected-note@-1 {{because it has a user-provided destructor}} \
+// expected-note@#tc-S4 {{'S4' defined here}}
+
+union U2 { // #tc-U2
+    U2(const U2&);
+    U2(U2&&);
+    B b;
+};
+static_assert(__is_trivially_copyable(U2));
+// expected-error@-1 {{static assertion failed due to requirement 
'__is_trivially_copyable(trivially_copyable::U2)'}} \
+// expected-note@-1 {{'U2' is not trivially copyable}} \
+// expected-note@-1 {{because it is a union with a user-declared copy 
constructor}} \
+// expected-note@-1 {{because it is a union with a user-declared move 
constructor}} \
+// expected-note@-1 {{because it has a deleted destructor}} \
+// expected-note@-1 {{because it has a non-trivially-copyable member 'b' of 
type 'B'}} \
+// expected-note@#tc-U2 {{'U2' defined here}}
+}

>From 8edd53d0554046a50320cfab9e0db163fb86268b Mon Sep 17 00:00:00 2001
From: Shamshura Egor <shamshurae...@gmail.com>
Date: Mon, 2 Jun 2025 09:41:32 +0000
Subject: [PATCH 2/7] Fixed check for trivial destructor using Dtr->isTrivial()
 now, removed union

---
 clang/lib/Sema/SemaTypeTraits.cpp             | 19 +-----------
 .../SemaCXX/type-traits-unsatisfied-diags.cpp | 29 -------------------
 2 files changed, 1 insertion(+), 47 deletions(-)

diff --git a/clang/lib/Sema/SemaTypeTraits.cpp 
b/clang/lib/Sema/SemaTypeTraits.cpp
index aaa5aff53fbc5..231b10efb6afe 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -2112,23 +2112,6 @@ static void DiagnoseNonTriviallyCopyableReason(Sema 
&SemaRef,
         << diag::TraitNotSatisfiedReason::DeletedDtr << 0
         << D->getDestructor()->getSourceRange();
 
-  if (D->isUnion()) {
-    auto DiagSPM = [&](CXXSpecialMemberKind K, bool Has) {
-      if (Has)
-        SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
-            << diag::TraitNotSatisfiedReason::UnionWithUserDeclaredSMF << K;
-    };
-    DiagSPM(CXXSpecialMemberKind::CopyConstructor,
-            D->hasUserDeclaredCopyConstructor());
-    DiagSPM(CXXSpecialMemberKind::CopyAssignment,
-            D->hasUserDeclaredCopyAssignment());
-    DiagSPM(CXXSpecialMemberKind::MoveConstructor,
-            D->hasUserDeclaredMoveConstructor());
-    DiagSPM(CXXSpecialMemberKind::MoveAssignment,
-            D->hasUserDeclaredMoveAssignment());
-    return;
-  }
-
   if (!D->hasSimpleMoveConstructor() && !D->hasSimpleCopyConstructor()) {
     const auto *Decl = cast<CXXConstructorDecl>(
         LookupSpecialMemberFromXValue(SemaRef, D, /*Assign=*/false));
@@ -2146,7 +2129,7 @@ static void DiagnoseNonTriviallyCopyableReason(Sema 
&SemaRef,
           << Decl->isMoveAssignmentOperator() << Decl->getSourceRange();
   }
   CXXDestructorDecl *Dtr = D->getDestructor();
-  if (Dtr && Dtr->isUserProvided() && !Dtr->isDefaulted())
+  if (Dtr && !Dtr->isTrivial())
     SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
         << diag::TraitNotSatisfiedReason::DeletedDtr << 1
         << Dtr->getSourceRange();
diff --git a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp 
b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
index 97510fe2eca9f..dc2a4b4adb9d0 100644
--- a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
+++ b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
@@ -184,21 +184,6 @@ struct S3 {
 };
 static_assert(__is_trivially_copyable(S3));
 
-union U { // #tc-U
-    U(const U&);
-    U(U&&);
-    U& operator=(const U&);
-    U& operator=(U&&);
-};
-static_assert(__is_trivially_copyable(U));
-// expected-error@-1 {{static assertion failed due to requirement 
'__is_trivially_copyable(trivially_copyable::U)'}} \
-// expected-note@-1 {{'U' is not trivially copyable}} \
-// expected-note@-1 {{because it is a union with a user-declared copy 
constructor}} \
-// expected-note@-1 {{because it is a union with a user-declared copy 
assignment operator}} \
-// expected-note@-1 {{because it is a union with a user-declared move 
constructor}} \
-// expected-note@-1 {{because it is a union with a user-declared move 
assignment operator}}
-// expected-note@#tc-U {{'U' defined here}}
-
 struct S4 { // #tc-S4
     ~S4();
     B b;
@@ -209,18 +194,4 @@ static_assert(__is_trivially_copyable(S4));
 // expected-note@-1 {{because it has a non-trivially-copyable member 'b' of 
type 'B'}} \
 // expected-note@-1 {{because it has a user-provided destructor}} \
 // expected-note@#tc-S4 {{'S4' defined here}}
-
-union U2 { // #tc-U2
-    U2(const U2&);
-    U2(U2&&);
-    B b;
-};
-static_assert(__is_trivially_copyable(U2));
-// expected-error@-1 {{static assertion failed due to requirement 
'__is_trivially_copyable(trivially_copyable::U2)'}} \
-// expected-note@-1 {{'U2' is not trivially copyable}} \
-// expected-note@-1 {{because it is a union with a user-declared copy 
constructor}} \
-// expected-note@-1 {{because it is a union with a user-declared move 
constructor}} \
-// expected-note@-1 {{because it has a deleted destructor}} \
-// expected-note@-1 {{because it has a non-trivially-copyable member 'b' of 
type 'B'}} \
-// expected-note@#tc-U2 {{'U2' defined here}}
 }

>From 65ca243f7cc3a41f3fe16f5c87401c4db4a32f5b Mon Sep 17 00:00:00 2001
From: Shamshura Egor <shamshurae...@gmail.com>
Date: Mon, 2 Jun 2025 11:49:47 +0000
Subject: [PATCH 3/7] Fixed for eligible special member functions

---
 clang/lib/Sema/SemaTypeTraits.cpp | 42 ++++++++++++++++++++-----------
 1 file changed, 28 insertions(+), 14 deletions(-)

diff --git a/clang/lib/Sema/SemaTypeTraits.cpp 
b/clang/lib/Sema/SemaTypeTraits.cpp
index 231b10efb6afe..75dc0558425e2 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -2112,21 +2112,35 @@ static void DiagnoseNonTriviallyCopyableReason(Sema 
&SemaRef,
         << diag::TraitNotSatisfiedReason::DeletedDtr << 0
         << D->getDestructor()->getSourceRange();
 
-  if (!D->hasSimpleMoveConstructor() && !D->hasSimpleCopyConstructor()) {
-    const auto *Decl = cast<CXXConstructorDecl>(
-        LookupSpecialMemberFromXValue(SemaRef, D, /*Assign=*/false));
-    if (Decl && Decl->isUserProvided())
-      SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
-          << diag::TraitNotSatisfiedReason::UserProvidedCtr
-          << Decl->isMoveConstructor() << Decl->getSourceRange();
-  }
-  if (!D->hasSimpleMoveAssignment() && !D->hasSimpleCopyAssignment()) {
-    CXXMethodDecl *Decl =
-        LookupSpecialMemberFromXValue(SemaRef, D, /*Assign=*/true);
-    if (Decl && Decl->isUserProvided())
+  for (const CXXMethodDecl *Method : D->methods()) {
+    if (Method->isIneligibleOrNotSelected() || Method->isTrivial() ||
+        !Method->isUserProvided()) {
+      continue;
+    }
+    auto SpecialMemberKind =
+        SemaRef.getDefaultedFunctionKind(Method).asSpecialMember();
+    switch (SpecialMemberKind) {
+    case CXXSpecialMemberKind::CopyConstructor:
+    case CXXSpecialMemberKind::MoveConstructor:
+    case CXXSpecialMemberKind::CopyAssignment:
+    case CXXSpecialMemberKind::MoveAssignment: {
+      bool IsAssignment =
+          SpecialMemberKind == CXXSpecialMemberKind::CopyAssignment ||
+          SpecialMemberKind == CXXSpecialMemberKind::MoveAssignment;
+      bool IsMove =
+          SpecialMemberKind == CXXSpecialMemberKind::MoveConstructor ||
+          SpecialMemberKind == CXXSpecialMemberKind::MoveAssignment;
+
       SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
-          << diag::TraitNotSatisfiedReason::UserProvidedAssign
-          << Decl->isMoveAssignmentOperator() << Decl->getSourceRange();
+          << (IsAssignment ? diag::TraitNotSatisfiedReason::UserProvidedAssign
+                           : diag::TraitNotSatisfiedReason::UserProvidedCtr)
+          << IsMove << Method->getSourceRange();
+      break;
+    }
+    default: {
+      break;
+    }
+    }
   }
   CXXDestructorDecl *Dtr = D->getDestructor();
   if (Dtr && !Dtr->isTrivial())

>From 9880d4f52c7d2d62fafc2732f7fb429485802465 Mon Sep 17 00:00:00 2001
From: Shamshura Egor <shamshurae...@gmail.com>
Date: Mon, 2 Jun 2025 11:59:09 +0000
Subject: [PATCH 4/7] Removed Arc lifetime

---
 clang/lib/Sema/SemaTypeTraits.cpp | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/clang/lib/Sema/SemaTypeTraits.cpp 
b/clang/lib/Sema/SemaTypeTraits.cpp
index 75dc0558425e2..8612c2f9c8977 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -2158,12 +2158,6 @@ static void DiagnoseNonTriviallyCopyableReason(Sema 
&SemaRef,
     SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
         << diag::TraitNotSatisfiedReason::Ref;
 
-  T = T.getNonReferenceType();
-
-  if (T.hasNonTrivialObjCLifetime())
-    SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
-        << diag::TraitNotSatisfiedReason::HasArcLifetime;
-
   const CXXRecordDecl *D = T->getAsCXXRecordDecl();
   if (!D || D->isInvalidDecl())
     return;

>From 2401565e26aa2677fda9d66b23dea414510b9814 Mon Sep 17 00:00:00 2001
From: Shamshura Egor <shamshurae...@gmail.com>
Date: Mon, 2 Jun 2025 14:38:01 +0000
Subject: [PATCH 5/7] Changed NR to NTR

---
 clang/include/clang/Basic/DiagnosticSemaKinds.td | 4 ++--
 clang/lib/Sema/SemaTypeTraits.cpp                | 6 +++---
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 748e0720c5ef5..fd1be3aafb8aa 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1775,8 +1775,8 @@ def note_unsatisfied_trait_reason
            "%HasArcLifetime{has an ARC lifetime qualifier}|"
            "%VLA{is a variably-modified type}|"
            "%VBase{has a virtual base %1}|"
-           "%NRBase{has a non-trivially-relocatable base %1}|"
-           "%NRField{has a non-trivially-relocatable member %1 of type %2}|"
+           "%NTRBase{has a non-trivially-relocatable base %1}|"
+           "%NTRField{has a non-trivially-relocatable member %1 of type %2}|"
            "%NTCBase{has a non-trivially-copyable base %1}|"
            "%NTCField{has a non-trivially-copyable member %1 of type %2}|"
            "%DeletedDtr{has a %select{deleted|user-provided}1 destructor}|"
diff --git a/clang/lib/Sema/SemaTypeTraits.cpp 
b/clang/lib/Sema/SemaTypeTraits.cpp
index 8612c2f9c8977..f053934ab8eeb 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -2000,15 +2000,15 @@ static void DiagnoseNonTriviallyRelocatableReason(Sema 
&SemaRef,
           << B.getSourceRange();
     if (!SemaRef.IsCXXTriviallyRelocatableType(B.getType()))
       SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
-          << diag::TraitNotSatisfiedReason::NRBase << B.getType()
+          << diag::TraitNotSatisfiedReason::NTRBase << B.getType()
           << B.getSourceRange();
   }
   for (const FieldDecl *Field : D->fields()) {
     if (!Field->getType()->isReferenceType() &&
         !SemaRef.IsCXXTriviallyRelocatableType(Field->getType()))
       SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
-          << diag::TraitNotSatisfiedReason::NRField << Field << 
Field->getType()
-          << Field->getSourceRange();
+          << diag::TraitNotSatisfiedReason::NTRField << Field
+          << Field->getType() << Field->getSourceRange();
   }
   if (D->hasDeletedDestructor())
     SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)

>From 94bec75372ff4be437041442153ae8440b00d5fa Mon Sep 17 00:00:00 2001
From: Shamshura Egor <shamshurae...@gmail.com>
Date: Mon, 2 Jun 2025 17:09:14 +0000
Subject: [PATCH 6/7] Added tests for non-trvial-copyable bases, for special
 members

---
 .../SemaCXX/type-traits-unsatisfied-diags.cpp | 71 +++++++++++++++++++
 1 file changed, 71 insertions(+)

diff --git a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp 
b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
index dc2a4b4adb9d0..f84d25d7b4ac2 100644
--- a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
+++ b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
@@ -194,4 +194,75 @@ static_assert(__is_trivially_copyable(S4));
 // expected-note@-1 {{because it has a non-trivially-copyable member 'b' of 
type 'B'}} \
 // expected-note@-1 {{because it has a user-provided destructor}} \
 // expected-note@#tc-S4 {{'S4' defined here}}
+
+struct B1 {
+    int & a;
+};
+
+struct B2 {
+    int & a;
+};
+
+struct S5 : virtual B1, virtual B2 { // #tc-S5
+};
+static_assert(__is_trivially_copyable(S5));
+// expected-error@-1 {{static assertion failed due to requirement 
'__is_trivially_copyable(trivially_copyable::S5)'}} \
+// expected-note@-1 {{'S5' is not trivially copyable}} \
+// expected-note@-1 {{because it has a virtual base 'B1'}} \
+// expected-note@-1 {{because it has a virtual base 'B2'}} \
+// expected-note@#tc-S5 {{'S5' defined here}}
+
+struct B3 {
+    ~B3();
+};
+
+struct B4 {
+    ~B4();
+};
+
+struct S6 : B3, B4 { // #tc-S6
+};
+static_assert(__is_trivially_copyable(S6));
+// expected-error@-1 {{static assertion failed due to requirement 
'__is_trivially_copyable(trivially_copyable::S6)'}} \
+// expected-note@-1 {{because it has a non-trivially-copyable base 'B3'}} \
+// expected-note@-1 {{because it has a non-trivially-copyable base 'B4'}} \
+// expected-note@-1 {{because it has a user-provided destructor}} \
+// expected-note@-1 {{'S6' is not trivially copyable}} \
+// expected-note@#tc-S6 {{'S6' defined here}}
+
+struct S7 { // #tc-S7
+    S7(const S7&);
+};
+static_assert(__is_trivially_copyable(S7));
+// expected-error@-1 {{static assertion failed due to requirement 
'__is_trivially_copyable(trivially_copyable::S7)'}} \
+// expected-note@-1 {{because it has a user provided copy constructor}} \
+// expected-note@-1 {{'S7' is not trivially copyable}} \
+// expected-note@#tc-S7 {{'S7' defined here}}
+
+struct S8 { // #tc-S8
+    S8(S8&&);
+};
+static_assert(__is_trivially_copyable(S8));
+// expected-error@-1 {{static assertion failed due to requirement 
'__is_trivially_copyable(trivially_copyable::S8)'}} \
+// expected-note@-1 {{because it has a user provided move constructor}} \
+// expected-note@-1 {{'S8' is not trivially copyable}} \
+// expected-note@#tc-S8 {{'S8' defined here}}
+
+struct S9 { // #tc-S9
+    S9& operator=(const S9&);
+};
+static_assert(__is_trivially_copyable(S9));
+// expected-error@-1 {{static assertion failed due to requirement 
'__is_trivially_copyable(trivially_copyable::S9)'}} \
+// expected-note@-1 {{because it has a user provided copy assignment 
operator}} \
+// expected-note@-1 {{'S9' is not trivially copyable}} \
+// expected-note@#tc-S9 {{'S9' defined here}}
+
+struct S10 { // #tc-S10
+    S10& operator=(S10&&);
+};
+static_assert(__is_trivially_copyable(S10));
+// expected-error@-1 {{static assertion failed due to requirement 
'__is_trivially_copyable(trivially_copyable::S10)'}} \
+// expected-note@-1 {{because it has a user provided move assignment 
operator}} \
+// expected-note@-1 {{'S10' is not trivially copyable}} \
+// expected-note@#tc-S10 {{'S10' defined here}}
 }

>From 8636714f7df406ec9d1e62c69b06031ae65a0df4 Mon Sep 17 00:00:00 2001
From: Shamshura Egor <shamshurae...@gmail.com>
Date: Mon, 2 Jun 2025 18:08:34 +0000
Subject: [PATCH 7/7] Removed extra isIneligibleOrNotSelected check

---
 clang/lib/Sema/SemaTypeTraits.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang/lib/Sema/SemaTypeTraits.cpp 
b/clang/lib/Sema/SemaTypeTraits.cpp
index f053934ab8eeb..ba41e4b125a9e 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -2113,8 +2113,7 @@ static void DiagnoseNonTriviallyCopyableReason(Sema 
&SemaRef,
         << D->getDestructor()->getSourceRange();
 
   for (const CXXMethodDecl *Method : D->methods()) {
-    if (Method->isIneligibleOrNotSelected() || Method->isTrivial() ||
-        !Method->isUserProvided()) {
+    if (Method->isTrivial() || !Method->isUserProvided()) {
       continue;
     }
     auto SpecialMemberKind =

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to