https://github.com/pesdarshan created 
https://github.com/llvm/llvm-project/pull/225487

Part of https://github.com/llvm/llvm-project/issues/141911

When std::is_trivially_copy_constructible<T> fails, Clang now explains why 
(user-provided copy ctor, deleted, inaccessible, non-trivial base/member, 
etc.), same as it already does for is_trivially_copyable.

There's no dedicated builtin for this trait it's implemented as 
__is_trivially_constructible(T, const T&), so I had to detect that shape 
specifically rather than relying on an existing name mapping.


>From f4f5367f1f3c305a9588f1516ccf5d900e8234ad Mon Sep 17 00:00:00 2001
From: Darshan N <[email protected]>
Date: Wed, 16 Sep 2026 11:31:47 +0530
Subject: [PATCH] Added explain is trivially copy constructible

---
 .../clang/Basic/DiagnosticSemaKinds.td        |   5 +
 clang/lib/Sema/SemaTypeTraits.cpp             | 149 +++++++++++++++---
 .../type-traits-unsatisfied-diags-std.cpp     |  79 ++++++++++
 .../SemaCXX/type-traits-unsatisfied-diags.cpp | 138 ++++++++++++++++
 4 files changed, 352 insertions(+), 19 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index fca68f292f6671..94d6a4cf9c5024 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1845,6 +1845,7 @@ def note_unsatisfied_trait
     : Note<"%0 is not %enum_select<TraitName>{"
            "%TriviallyRelocatable{trivially relocatable}|"
            "%TriviallyCopyable{trivially copyable}|"
+           "%TriviallyCopyConstructible{trivially copy constructible}|"
            "%Empty{empty}|"
            "%StandardLayout{standard-layout}|"
            "%Aggregate{aggregate}|"
@@ -1867,6 +1868,8 @@ def note_unsatisfied_trait_reason
            "%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}|"
+           "%NTCCBase{has a non-trivially-copy-constructible base %1}|"
+           "%NTCCField{has a non-trivially-copy-constructible member %1 of 
type %2}|"
            "%NonEmptyMember{has a non-static data member %1 of type %2}|"
            "%PolymorphicType{is a polymorphic type}|"
            "%VirtualFunction{has a virtual function %1}|"
@@ -1885,6 +1888,8 @@ def note_unsatisfied_trait_reason
            "%InheritedCtr{has an inherited constructor}|"
            "%DeletedCtr{has a deleted %select{copy|move}1 "
            "constructor}|"
+           "%InaccessibleCtr{has an inaccessible %select{copy|move}1 "
+           "constructor}|"
            "%UserProvidedAssign{has a user provided %select{copy|move}1 "
            "assignment operator}|"
            "%DeletedAssign{has a deleted %select{copy|move}1 "
diff --git a/clang/lib/Sema/SemaTypeTraits.cpp 
b/clang/lib/Sema/SemaTypeTraits.cpp
index cb30ff9fd02da9..2804c6fd1483f0 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -2016,6 +2016,22 @@ static std::optional<TypeTrait> 
StdNameToTypeTrait(StringRef Name) {
 using ExtractedTypeTraitInfo =
     std::optional<std::pair<TypeTrait, llvm::SmallVector<QualType, 1>>>;
 
+// Synthesize args for std::is_trivially_copy_constructible<T>, which wraps
+// __is_trivially_constructible but is not in the StdName table because it
+// fixes its own argument list.
+static ExtractedTypeTraitInfo
+SynthesizeTriviallyConstructibleArgs(ASTContext &Ctx, StringRef Name,
+                                     ArrayRef<QualType> TemplateArgs) {
+  if (TemplateArgs.size() != 1)
+    return std::nullopt;
+  if (Name != "is_trivially_copy_constructible")
+    return std::nullopt;
+  // std::is_trivially_copy_constructible<T> == 
__is_trivially_constructible(T, const T&)
+  QualType T = TemplateArgs[0];
+  QualType ConstTRef = Ctx.getLValueReferenceType(T.withConst());
+  return {{TT_IsTriviallyConstructible, {T, ConstTRef}}};
+}
+
 // Recognize type traits that are builting type traits, or known standard
 // type traits in <type_traits>. Note that at this point we assume the
 // trait evaluated to false, so we need only to recognize the shape of the
@@ -2024,6 +2040,21 @@ static ExtractedTypeTraitInfo 
ExtractTypeTraitFromExpression(const Expr *E) {
   llvm::SmallVector<QualType, 1> Args;
   std::optional<TypeTrait> Trait;
 
+  // Collect type arguments from a template argument list into Args.
+  // Packs are flattened; non-type arguments are silently skipped (they can
+  // appear in library templates whose argument lists we don't control).
+  auto CollectTypeArgs = [&Args](auto Range) {
+    for (const auto &Arg : Range) {
+      if (Arg.getKind() == TemplateArgument::ArgKind::Pack) {
+        for (const auto &Inner : Arg.pack_elements())
+          if (Inner.getKind() == TemplateArgument::ArgKind::Type)
+            Args.push_back(Inner.getAsType());
+      } else if (Arg.getKind() == TemplateArgument::ArgKind::Type) {
+        Args.push_back(Arg.getAsType());
+      }
+    }
+  };
+
   // builtins
   if (const auto *TraitExpr = dyn_cast<TypeTraitExpr>(E)) {
     Trait = TraitExpr->getTrait();
@@ -2043,20 +2074,14 @@ static ExtractedTypeTraitInfo 
ExtractTypeTraitFromExpression(const Expr *E) {
     StringRef Name = VD->getIdentifier()->getName();
     if (!Name.consume_back("_v"))
       return std::nullopt;
+    // First try the direct StdName mapping.
     Trait = StdNameToTypeTrait(Name);
-    if (!Trait)
-      return std::nullopt;
-    for (const auto &Arg : VD->getTemplateArgs().asArray()) {
-      if (Arg.getKind() == TemplateArgument::ArgKind::Pack) {
-        for (const auto &InnerArg : Arg.pack_elements())
-          Args.push_back(InnerArg.getAsType());
-      } else if (Arg.getKind() == TemplateArgument::ArgKind::Type) {
-        Args.push_back(Arg.getAsType());
-      } else {
-        llvm_unreachable("Unexpected kind");
-      }
-    }
-    return {{Trait.value(), std::move(Args)}};
+    CollectTypeArgs(VD->getTemplateArgs().asArray());
+    if (Trait)
+      return {{Trait.value(), std::move(Args)}};
+    // Fall back to traits that synthesize their own arg list.
+    return SynthesizeTriviallyConstructibleArgs(
+        VD->getASTContext(), Name, Args);
   }
 
   // std::is_xxx<>::value
@@ -2071,12 +2096,15 @@ static ExtractedTypeTraitInfo 
ExtractTypeTraitFromExpression(const Expr *E) {
     const TemplateDecl *D = Ts->getTemplateName().getAsTemplateDecl();
     if (!D || !D->isInStdNamespace())
       return std::nullopt;
-    Trait = StdNameToTypeTrait(D->getIdentifier()->getName());
-    if (!Trait)
-      return std::nullopt;
-    for (const auto &Arg : Ts->template_arguments())
-      Args.push_back(Arg.getAsType());
-    return {{Trait.value(), std::move(Args)}};
+    StringRef Name = D->getIdentifier()->getName();
+    // First try the direct StdName mapping.
+    Trait = StdNameToTypeTrait(Name);
+    CollectTypeArgs(Ts->template_arguments());
+    if (Trait)
+      return {{Trait.value(), std::move(Args)}};
+    // Fall back to traits that synthesize their own arg list.
+    return SynthesizeTriviallyConstructibleArgs(
+        D->getASTContext(), Name, Args);
   }
   return std::nullopt;
 }
@@ -2312,6 +2340,78 @@ static void DiagnoseNonTriviallyCopyableReason(Sema 
&SemaRef,
   SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D;
 }
 
+static void DiagnoseNonTriviallyCopyConstructibleReason(Sema &SemaRef,
+                                                        SourceLocation Loc,
+                                                        const CXXRecordDecl 
*D) {
+  for (const CXXBaseSpecifier &B : D->bases()) {
+    if (B.isVirtual())
+      SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+          << diag::TraitNotSatisfiedReason::VBase << B.getType()
+          << B.getSourceRange();
+    const CXXRecordDecl *BD = B.getType()->getAsCXXRecordDecl();
+    if (BD && BD->hasNonTrivialCopyConstructor())
+      SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+          << diag::TraitNotSatisfiedReason::NTCCBase << B.getType()
+          << B.getSourceRange();
+  }
+
+  for (const FieldDecl *F : D->fields()) {
+    // Use getBaseElementType to see through array types (e.g. NTBase arr[2]).
+    // Print the declared field type so the note matches the source.
+    QualType ElemTy = SemaRef.Context.getBaseElementType(F->getType());
+    const CXXRecordDecl *FD = ElemTy->getAsCXXRecordDecl();
+    if (FD && FD->hasNonTrivialCopyConstructor())
+      SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+          << diag::TraitNotSatisfiedReason::NTCCField << F << F->getType()
+          << F->getSourceRange();
+  }
+
+  if (D->isPolymorphic())
+    SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+        << diag::TraitNotSatisfiedReason::PolymorphicType;
+
+  for (const CXXConstructorDecl *Ctor : D->ctors()) {
+    if (!Ctor->isCopyConstructor())
+      continue;
+    if (Ctor->isDeleted())
+      SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+          << diag::TraitNotSatisfiedReason::DeletedCtr << /*copy*/ 0
+          << Ctor->getSourceRange();
+    else if (Ctor->isUserProvided())
+      SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+          << diag::TraitNotSatisfiedReason::UserProvidedCtr << /*copy*/ 0
+          << Ctor->getSourceRange();
+    else if (Ctor->getAccess() != AS_public)
+      SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+          << diag::TraitNotSatisfiedReason::InaccessibleCtr << /*copy*/ 0
+          << Ctor->getSourceRange();
+  }
+}
+
+static void DiagnoseNonTriviallyCopyConstructibleReason(Sema &SemaRef,
+                                                        SourceLocation Loc,
+                                                        QualType T) {
+  SemaRef.Diag(Loc, diag::note_unsatisfied_trait)
+      << T << diag::TraitName::TriviallyCopyConstructible;
+
+  if (T->isVoidType())
+    SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+        << diag::TraitNotSatisfiedReason::CVVoidType;
+  else if (T->isFunctionType())
+    SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+        << diag::TraitNotSatisfiedReason::FunctionType;
+  else if (T->isIncompleteArrayType())
+    SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+        << diag::TraitNotSatisfiedReason::IncompleteArrayType;
+
+  const CXXRecordDecl *D = T->getAsCXXRecordDecl();
+  if (!D || D->isInvalidDecl() || !D->hasDefinition())
+    return;
+
+  DiagnoseNonTriviallyCopyConstructibleReason(SemaRef, Loc, D);
+  SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D;
+}
+
 static void DiagnoseNonAssignableReason(Sema &SemaRef, SourceLocation Loc,
                                         QualType T, QualType U) {
   const CXXRecordDecl *D = T->getAsCXXRecordDecl();
@@ -2794,6 +2894,17 @@ void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
   case UTT_IsAbstract:
     DiagnoseNonAbstractReason(*this, E->getBeginLoc(), Args[0]);
     break;
+  case TT_IsTriviallyConstructible:
+    if (Args.size() == 2) {
+      // Check that the second arg is `cv T &` (copy-construction shape).
+      // Args[1] is the source type as it appears in 
__is_trivially_constructible.
+      if (const auto *LVRef = Args[1]->getAs<LValueReferenceType>()) {
+        if (Context.hasSameUnqualifiedType(Args[0], LVRef->getPointeeType()))
+          DiagnoseNonTriviallyCopyConstructibleReason(*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 8a9f3bc400d206..dc052adfe3b892 100644
--- a/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
+++ b/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
@@ -73,6 +73,14 @@ struct is_abstract {
 template <typename T>
 constexpr bool is_abstract_v = __is_abstract(T);
 
+template <typename T>
+struct is_trivially_copy_constructible {
+    static constexpr bool value = __is_trivially_constructible(T, const T&);
+};
+template <typename T>
+constexpr bool is_trivially_copy_constructible_v =
+    __is_trivially_constructible(T, const T&);
+
 #endif
 
 #ifdef STD2
@@ -167,6 +175,16 @@ using is_abstract = __details_is_abstract<T>;
 template <typename T>
 constexpr bool is_abstract_v = __is_abstract(T);
 
+template <typename T>
+struct __details_is_trivially_copy_constructible {
+    static constexpr bool value = __is_trivially_constructible(T, const T&);
+};
+template <typename T>
+using is_trivially_copy_constructible = 
__details_is_trivially_copy_constructible<T>;
+template <typename T>
+constexpr bool is_trivially_copy_constructible_v =
+    __is_trivially_constructible(T, const T&);
+
 #endif
 
 
@@ -252,6 +270,16 @@ using is_abstract = __details_is_abstract<T>;
 template <typename T>
 constexpr bool is_abstract_v = is_abstract<T>::value;
 
+template <typename T>
+struct __details_is_trivially_copy_constructible
+    : bool_constant<__is_trivially_constructible(T, const T&)> {};
+template <typename T>
+using is_trivially_copy_constructible =
+    __details_is_trivially_copy_constructible<T>;
+template <typename T>
+constexpr bool is_trivially_copy_constructible_v =
+    is_trivially_copy_constructible<T>::value;
+
 #endif
 }
 
@@ -277,6 +305,32 @@ static_assert(std::is_trivially_copyable_v<int&>);
 // expected-note@-1 {{'int &' is not trivially copyable}} \
 // expected-note@-1 {{because it is a reference type}}
 
+struct UserProvidedCopyCtor { // #tcc-std-UserProvided
+    UserProvidedCopyCtor(const UserProvidedCopyCtor&) {}
+};
+
+// std::is_trivially_copy_constructible<T>::value path
+static_assert(std::is_trivially_copy_constructible<int>::value);
+
+static_assert(std::is_trivially_copy_constructible<UserProvidedCopyCtor>::value);
+// expected-error-re@-1 {{static assertion failed due to requirement 
'std::{{.*}}is_trivially_copy_constructible<{{.*}}UserProvidedCopyCtor>::value'}}
 \
+// expected-note@-1 {{'UserProvidedCopyCtor' is not trivially copy 
constructible}} \
+// expected-note@-1 {{because it has a user provided copy constructor}} \
+// expected-note@#tcc-std-UserProvided {{'UserProvidedCopyCtor' defined here}}
+
+// std::is_trivially_copy_constructible_v<T> path
+static_assert(std::is_trivially_copy_constructible_v<int>);
+
+static_assert(std::is_trivially_copy_constructible_v<UserProvidedCopyCtor>);
+// expected-error@-1 {{static assertion failed due to requirement 
'std::is_trivially_copy_constructible_v<UserProvidedCopyCtor>'}} \
+// expected-note@-1 {{'UserProvidedCopyCtor' is not trivially copy 
constructible}} \
+// expected-note@-1 {{because it has a user provided copy constructor}} \
+// expected-note@#tcc-std-UserProvided {{'UserProvidedCopyCtor' defined here}}
+
+
+// Positive: references are trivially copy constructible (must produce no 
diagnostic)
+static_assert(std::is_trivially_copy_constructible<int&>::value);
+static_assert(std::is_trivially_copy_constructible_v<int&>);
 
  // Direct tests
  static_assert(std::is_standard_layout<int>::value);
@@ -493,6 +547,14 @@ concept C2 = std::is_trivially_copyable_v<T>; // #concept4
 
 template <C2 T> void g2();  // #cand4
 
+template <typename T>
+requires std::is_trivially_copy_constructible<T>::value void f6();  // #cand11
+
+template <typename T>
+concept C6 = std::is_trivially_copy_constructible_v<T>; // #concept11
+
+template <C6 T> void g6();  // #cand12
+
 template <typename T, typename U>
 requires std::is_assignable<T, U>::value void f4();  // #cand7
 
@@ -549,6 +611,23 @@ void test() {
     // expected-note@#concept4 {{'int &' is not trivially copyable}} \
     // expected-note@#concept4 {{because it is a reference type}}
 
+    f6<UserProvidedCopyCtor>();
+    // expected-error@-1 {{no matching function for call to 'f6'}} \
+    // expected-note@#cand11 {{candidate template ignored: constraints not 
satisfied [with T = UserProvidedCopyCtor]}} \
+    // expected-note-re@#cand11 {{because 
'{{.*}}is_trivially_copy_constructible<{{.*}}UserProvidedCopyCtor>::value' 
evaluated to false}} \
+    // expected-note@#cand11 {{'UserProvidedCopyCtor' is not trivially copy 
constructible}} \
+    // expected-note@#cand11 {{because it has a user provided copy 
constructor}} \
+    // expected-note@#tcc-std-UserProvided {{'UserProvidedCopyCtor' defined 
here}}
+
+    g6<UserProvidedCopyCtor>();
+    // expected-error@-1 {{no matching function for call to 'g6'}} \
+    // expected-note@#cand12 {{candidate template ignored: constraints not 
satisfied [with T = UserProvidedCopyCtor]}} \
+    // expected-note@#cand12 {{because 'UserProvidedCopyCtor' does not satisfy 
'C6'}} \
+    // expected-note@#concept11 {{because 
'std::is_trivially_copy_constructible_v<UserProvidedCopyCtor>' evaluated to 
false}} \
+    // expected-note@#concept11 {{'UserProvidedCopyCtor' is not trivially copy 
constructible}} \
+    // expected-note@#concept11 {{because it has a user provided copy 
constructor}} \
+    // expected-note@#tcc-std-UserProvided {{'UserProvidedCopyCtor' defined 
here}}
+
     f4<int&, void>();
     // expected-error@-1 {{no matching function for call to 'f4'}} \
     // expected-note@#cand7 {{candidate template ignored: constraints not 
satisfied [with T = int &, U = void]}} \
diff --git a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp 
b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
index 3bde5b06a3aba4..c0271291ada770 100644
--- a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
+++ b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
@@ -892,3 +892,141 @@ static_assert(__is_abstract(U));
 // expected-note@-1 {{because it is not a struct or class type}}
 
 }
+
+namespace trivially_copy_constructible {
+
+// Case 1: user-provided copy constructor
+struct UserProvided { // #tcc-UserProvided
+    UserProvided(const UserProvided&) {}
+};
+static_assert(__is_trivially_constructible(UserProvided, const UserProvided&));
+// expected-error@-1 {{static assertion failed due to requirement 
'__is_trivially_constructible(trivially_copy_constructible::UserProvided, const 
trivially_copy_constructible::UserProvided &)'}} \
+// expected-note@-1  {{'UserProvided' is not trivially copy constructible}} \
+// expected-note@-1  {{because it has a user provided copy constructor}} \
+// expected-note@#tcc-UserProvided {{'UserProvided' defined here}}
+
+// Case 2: deleted copy constructor
+struct DeletedCopy { // #tcc-DeletedCopy
+    DeletedCopy(const DeletedCopy&) = delete;
+};
+static_assert(__is_trivially_constructible(DeletedCopy, const DeletedCopy&));
+// expected-error@-1 {{static assertion failed due to requirement 
'__is_trivially_constructible(trivially_copy_constructible::DeletedCopy, const 
trivially_copy_constructible::DeletedCopy &)'}} \
+// expected-note@-1  {{'DeletedCopy' is not trivially copy constructible}} \
+// expected-note@-1  {{because it has a deleted copy constructor}} \
+// expected-note@#tcc-DeletedCopy {{'DeletedCopy' defined here}}
+
+// Case 3: polymorphic type (virtual function introduces non-trivial copy)
+struct Polymorphic { // #tcc-Polymorphic
+    virtual void f();
+};
+static_assert(__is_trivially_constructible(Polymorphic, const Polymorphic&));
+// expected-error@-1 {{static assertion failed due to requirement 
'__is_trivially_constructible(trivially_copy_constructible::Polymorphic, const 
trivially_copy_constructible::Polymorphic &)'}} \
+// expected-note@-1  {{'Polymorphic' is not trivially copy constructible}} \
+// expected-note@-1  {{because it is a polymorphic type}} \
+// expected-note@#tcc-Polymorphic {{'Polymorphic' defined here}}
+
+// Case 4: virtual base
+struct VBase {}; // #tcc-VBase
+struct WithVBase : virtual VBase { // #tcc-WithVBase
+};
+static_assert(__is_trivially_constructible(WithVBase, const WithVBase&));
+// expected-error@-1 {{static assertion failed due to requirement 
'__is_trivially_constructible(trivially_copy_constructible::WithVBase, const 
trivially_copy_constructible::WithVBase &)'}} \
+// expected-note@-1  {{'WithVBase' is not trivially copy constructible}} \
+// expected-note@-1  {{because it has a virtual base 'VBase'}} \
+// expected-note@#tcc-WithVBase {{'WithVBase' defined here}}
+
+// Case 5: base with non-trivial copy constructor
+struct NTBase { // #tcc-NTBase
+    NTBase(const NTBase&) {}
+};
+struct WithNTBase : NTBase { // #tcc-WithNTBase
+};
+static_assert(__is_trivially_constructible(WithNTBase, const WithNTBase&));
+// expected-error@-1 {{static assertion failed due to requirement 
'__is_trivially_constructible(trivially_copy_constructible::WithNTBase, const 
trivially_copy_constructible::WithNTBase &)'}} \
+// expected-note@-1  {{'WithNTBase' is not trivially copy constructible}} \
+// expected-note@-1  {{because it has a non-trivially-copy-constructible base 
'NTBase'}} \
+// expected-note@#tcc-WithNTBase {{'WithNTBase' defined here}}
+
+// Case 6: member with non-trivial copy constructor
+struct WithNTMember { // #tcc-WithNTMember
+    NTBase m;
+};
+static_assert(__is_trivially_constructible(WithNTMember, const WithNTMember&));
+// expected-error@-1 {{static assertion failed due to requirement 
'__is_trivially_constructible(trivially_copy_constructible::WithNTMember, const 
trivially_copy_constructible::WithNTMember &)'}} \
+// expected-note@-1  {{'WithNTMember' is not trivially copy constructible}} \
+// expected-note@-1  {{because it has a non-trivially-copy-constructible 
member 'm' of type 'NTBase'}} \
+// expected-note@#tcc-WithNTMember {{'WithNTMember' defined here}}
+
+// Case 7: array member with non-trivial copy constructor
+struct WithArrayMember { // #tcc-WithArrayMember
+    NTBase arr[2];
+};
+static_assert(__is_trivially_constructible(WithArrayMember, const 
WithArrayMember&));
+// expected-error@-1 {{static assertion failed due to requirement 
'__is_trivially_constructible(trivially_copy_constructible::WithArrayMember, 
const trivially_copy_constructible::WithArrayMember &)'}} \
+// expected-note@-1  {{'WithArrayMember' is not trivially copy constructible}} 
\
+// expected-note@-1  {{because it has a non-trivially-copy-constructible 
member 'arr' of type 'NTBase[2]'}} \
+// expected-note@#tcc-WithArrayMember {{'WithArrayMember' defined here}}
+
+// Case 8: inaccessible (private) copy constructor
+struct PrivateCopy { // #tcc-PrivateCopy
+private:
+    PrivateCopy(const PrivateCopy&) = default;
+};
+static_assert(__is_trivially_constructible(PrivateCopy, const PrivateCopy&));
+// expected-error@-1 {{static assertion failed due to requirement 
'__is_trivially_constructible(trivially_copy_constructible::PrivateCopy, const 
trivially_copy_constructible::PrivateCopy &)'}} \
+// expected-note@-1  {{'PrivateCopy' is not trivially copy constructible}} \
+// expected-note@-1  {{because it has an inaccessible copy constructor}} \
+// expected-note@#tcc-PrivateCopy {{'PrivateCopy' defined here}}
+
+// Case 9: non-const lvalue reference shape — also recognised as copy 
construction
+struct NonConstRef { // #tcc-NonConstRef
+    NonConstRef(NonConstRef&) {}
+};
+static_assert(__is_trivially_constructible(NonConstRef, NonConstRef&));
+// expected-error@-1 {{static assertion failed due to requirement 
'__is_trivially_constructible(trivially_copy_constructible::NonConstRef, 
trivially_copy_constructible::NonConstRef &)'}} \
+// expected-note@-1  {{'NonConstRef' is not trivially copy constructible}} \
+// expected-note@-1  {{because it has a user provided copy constructor}} \
+// expected-note@#tcc-NonConstRef {{'NonConstRef' defined here}}
+
+// Case 10: multiple reasons at once
+struct Multi : virtual VBase, NTBase { // #tcc-Multi
+    NTBase m;
+};
+static_assert(__is_trivially_constructible(Multi, const Multi&));
+// expected-error@-1 {{static assertion failed due to requirement 
'__is_trivially_constructible(trivially_copy_constructible::Multi, const 
trivially_copy_constructible::Multi &)'}} \
+// expected-note@-1  {{'Multi' is not trivially copy constructible}} \
+// expected-note@-1  {{because it has a virtual base 'VBase'}} \
+// expected-note@-1  {{because it has a non-trivially-copy-constructible base 
'NTBase'}} \
+// expected-note@-1  {{because it has a non-trivially-copy-constructible 
member 'm' of type 'NTBase'}} \
+// expected-note@#tcc-Multi {{'Multi' defined here}}
+
+// Case 11: presence of a non-copy constructor must not confuse the walk
+struct MultiCtor { // #tcc-MultiCtor
+    MultiCtor(int) {}
+    MultiCtor(const MultiCtor&) = delete;
+};
+static_assert(__is_trivially_constructible(MultiCtor, const MultiCtor&));
+// expected-error@-1 {{static assertion failed due to requirement 
'__is_trivially_constructible(trivially_copy_constructible::MultiCtor, const 
trivially_copy_constructible::MultiCtor &)'}} \
+// expected-note@-1  {{'MultiCtor' is not trivially copy constructible}} \
+// expected-note@-1  {{because it has a deleted copy constructor}} \
+// expected-note@#tcc-MultiCtor {{'MultiCtor' defined here}}
+
+// Positive cases — must produce no diagnostic
+struct Trivial { int x; };
+static_assert(__is_trivially_constructible(Trivial, const Trivial&));
+static_assert(__is_trivially_constructible(int, const int&));
+// References are trivially copy constructible
+static_assert(__is_trivially_constructible(int&, int&));
+
+// Misclassification guard: 2-arg non-copy shape must NOT trigger copy 
diagnostic
+struct HasIntCtor { HasIntCtor(int) {} };
+static_assert(__is_trivially_constructible(HasIntCtor, int));
+// expected-error@-1 {{static assertion failed due to requirement 
'__is_trivially_constructible(trivially_copy_constructible::HasIntCtor, int)'}}
+
+// Dependent context — must not crash
+template <typename T>
+void dependent() {
+  static_assert(__is_trivially_constructible(T, const T&));
+}
+
+}

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

Reply via email to