diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -1379,6 +1379,11 @@ void CXXRecordDecl::addedEligibleSpecialMemberFunction(const CXXMethodDecl *MD, unsigned SMKind) { + if (MD->getDescribedFunctionTemplate()) + // This happens only when we get a template default constructor. + // We don't want it to affect DeclaredNonTrivialSpecialMembers because + // it shouldn't make a class non-trivial. (GH59206) + return; if (const auto *DD = dyn_cast(MD)) { if (DD->isUserProvided()) data().HasIrrelevantDestructor = false; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -18193,8 +18193,11 @@ CXXMethodDecl *M1, CXXMethodDecl *M2, Sema::CXXSpecialMember CSM) { + // We don't compare templates to non-templates: See + // https://github.com/llvm/llvm-project/issues/59206 if (CSM == Sema::CXXDefaultConstructor) - return true; + return bool(M1->getDescribedFunctionTemplate()) == + bool(M2->getDescribedFunctionTemplate()); if (!Context.hasSameType(M1->getParamDecl(0)->getType(), M2->getParamDecl(0)->getType())) return false; diff --git a/clang/test/SemaCXX/constrained-special-member-functions.cpp b/clang/test/SemaCXX/constrained-special-member-functions.cpp --- a/clang/test/SemaCXX/constrained-special-member-functions.cpp +++ b/clang/test/SemaCXX/constrained-special-member-functions.cpp @@ -225,3 +225,41 @@ S<2, 2> s2; } } + +namespace GH59206 { + +struct A { + A() = default; //eligible, second constructor unsatisfied + template + A(Args&&... args) requires (sizeof...(Args) > 0) {} +}; + +struct B { + B() = default; //ineligible, second constructor more constrained + template + B(Args&&... args) requires (sizeof...(Args) == 0) {} +}; + +struct C { + C() = default; //eligible, but + template //also eligible and non-trivial + C(Args&&... args) {} +}; + +struct D : B {}; + +static_assert(__is_trivially_copyable(A), ""); +static_assert(__is_trivially_copyable(B), ""); +static_assert(__is_trivially_copyable(C), ""); +static_assert(__is_trivially_copyable(D), ""); + +static_assert(__is_trivial(A), ""); +static_assert(__is_trivial(B), ""); +static_assert(__is_trivial(C), ""); +static_assert(__is_trivial(D), ""); +static_assert(__is_trivially_constructible(A), ""); +static_assert(__is_trivially_constructible(B), ""); +static_assert(__is_trivially_constructible(C), ""); +static_assert(__is_trivially_constructible(D), ""); + +}