https://github.com/Darshan-N3 updated https://github.com/llvm/llvm-project/pull/225487
>From e6af9ed619fba78bc5b1c9fb42e35d1d4001e97c 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 | 150 +++++++++++++++--- .../type-traits-unsatisfied-diags-std.cpp | 79 +++++++++ .../SemaCXX/type-traits-unsatisfied-diags.cpp | 138 ++++++++++++++++ 4 files changed, 353 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..d1ce66b57c35c8 100644 --- a/clang/lib/Sema/SemaTypeTraits.cpp +++ b/clang/lib/Sema/SemaTypeTraits.cpp @@ -2016,6 +2016,23 @@ 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 +2041,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 +2075,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 +2097,14 @@ 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,18 @@ 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
