https://github.com/sdkrystian updated https://github.com/llvm/llvm-project/pull/113464
>From 7542bda555601ed537dd9bacde65537021cf402d Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski <sdkryst...@gmail.com> Date: Wed, 23 Oct 2024 10:28:23 -0400 Subject: [PATCH 1/4] [Clang][Sema] Ignore previous partial specializations of member class templates explicitly specialized for a implicitly instantiated class template specialization --- clang/lib/Sema/SemaTemplate.cpp | 13 +++++ clang/lib/Sema/SemaTemplateInstantiate.cpp | 34 ++++++++++-- .../temp.spec.partial.member/p2.cpp | 53 +++++++++++++++++++ 3 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 clang/test/CXX/temp/temp.decls/temp.spec.partial/temp.spec.partial.member/p2.cpp diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index fcf05798d9c709..83e8447c0cdc0f 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -4383,6 +4383,19 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) { VarTemplatePartialSpecializationDecl *Partial = PartialSpecs[I]; + // C++ [temp.spec.partial.member]p2: + // If the primary member template is explicitly specialized for a given + // (implicit) specialization of the enclosing class template, the partial + // specializations of the member template are ignored for this + // specialization of the enclosing class template. If a partial + // specialization of the member template is explicitly specialized for a + // given (implicit) specialization of the enclosing class template, the + // primary member template and its other partial specializations are still + // considered for this specialization of the enclosing class template. + if (Template->isMemberSpecialization() && + !Partial->isMemberSpecialization()) + continue; + TemplateDeductionInfo Info(FailedCandidates.getLocation()); if (TemplateDeductionResult Result = diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index dea97bfce532c9..6e1492f8cd447e 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -3978,11 +3978,23 @@ bool Sema::usesPartialOrExplicitSpecialization( return true; SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs; - ClassTemplateSpec->getSpecializedTemplate() - ->getPartialSpecializations(PartialSpecs); - for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) { + ClassTemplateDecl *CTD = ClassTemplateSpec->getSpecializedTemplate(); + CTD->getPartialSpecializations(PartialSpecs); + for (ClassTemplatePartialSpecializationDecl *CTPSD : PartialSpecs) { + // C++ [temp.spec.partial.member]p2: + // If the primary member template is explicitly specialized for a given + // (implicit) specialization of the enclosing class template, the partial + // specializations of the member template are ignored for this + // specialization of the enclosing class template. If a partial + // specialization of the member template is explicitly specialized for a + // given (implicit) specialization of the enclosing class template, the + // primary member template and its other partial specializations are still + // considered for this specialization of the enclosing class template. + if (CTD->isMemberSpecialization() && !CTPSD->isMemberSpecialization()) + continue; + TemplateDeductionInfo Info(Loc); - if (DeduceTemplateArguments(PartialSpecs[I], + if (DeduceTemplateArguments(CTPSD, ClassTemplateSpec->getTemplateArgs().asArray(), Info) == TemplateDeductionResult::Success) return true; @@ -4027,6 +4039,20 @@ getPatternForClassTemplateSpecialization( TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation); for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) { ClassTemplatePartialSpecializationDecl *Partial = PartialSpecs[I]; + // C++ [temp.spec.partial.member]p2: + // If the primary member template is explicitly specialized for a given + // (implicit) specialization of the enclosing class template, the + // partial specializations of the member template are ignored for this + // specialization of the enclosing class template. If a partial + // specialization of the member template is explicitly specialized for a + // given (implicit) specialization of the enclosing class template, the + // primary member template and its other partial specializations are + // still considered for this specialization of the enclosing class + // template. + if (Template->isMemberSpecialization() && + !Partial->isMemberSpecialization()) + continue; + TemplateDeductionInfo Info(FailedCandidates.getLocation()); if (TemplateDeductionResult Result = S.DeduceTemplateArguments( Partial, ClassTemplateSpec->getTemplateArgs().asArray(), Info); diff --git a/clang/test/CXX/temp/temp.decls/temp.spec.partial/temp.spec.partial.member/p2.cpp b/clang/test/CXX/temp/temp.decls/temp.spec.partial/temp.spec.partial.member/p2.cpp new file mode 100644 index 00000000000000..9a71da4bae37ca --- /dev/null +++ b/clang/test/CXX/temp/temp.decls/temp.spec.partial/temp.spec.partial.member/p2.cpp @@ -0,0 +1,53 @@ +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s +// expected-no-diagnostics + +template<typename T> +struct A { + template<typename U> + struct B { + static constexpr int y = 0; + }; + + template<typename U> + struct B<U*> { + static constexpr int y = 1; + }; + + template<typename U> + static constexpr int x = 0; + + template<typename U> + static constexpr int x<U*> = 1; +}; + +static_assert(A<short>::B<int>::y == 0); +static_assert(A<short>::B<int*>::y == 1); +static_assert(A<short>::x<int> == 0); +static_assert(A<short>::x<int*> == 1); + +template<> +template<typename U> +struct A<long>::B { + static constexpr int y = 2; +}; + +template<> +template<typename U> +struct A<long>::B<U&> { + static constexpr int y = 3; +}; + +template<> +template<typename U> +constexpr int A<long>::x = 2; + +template<> +template<typename U> +constexpr int A<long>::x<U&> = 3; + +static_assert(A<long>::B<int>::y == 2); +static_assert(A<long>::B<int*>::y == 2); +static_assert(A<long>::B<int&>::y == 3); +static_assert(A<long>::x<int> == 2); +static_assert(A<long>::x<int*> == 2); +static_assert(A<long>::x<int&> == 3); >From f2858862e71543a80a1f9790897ff6ba6e68d547 Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski <sdkryst...@gmail.com> Date: Wed, 30 Oct 2024 09:43:47 -0400 Subject: [PATCH 2/4] [FOLD] use most recent declaration --- clang/lib/Sema/SemaTemplate.cpp | 7 +++---- clang/lib/Sema/SemaTemplateInstantiate.cpp | 10 +++++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 83e8447c0cdc0f..4503e60cff8c2f 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -4381,8 +4381,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, SmallVector<VarTemplatePartialSpecializationDecl *, 4> PartialSpecs; Template->getPartialSpecializations(PartialSpecs); - for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) { - VarTemplatePartialSpecializationDecl *Partial = PartialSpecs[I]; + for (VarTemplatePartialSpecializationDecl *Partial : PartialSpecs) { // C++ [temp.spec.partial.member]p2: // If the primary member template is explicitly specialized for a given // (implicit) specialization of the enclosing class template, the partial @@ -4392,8 +4391,8 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, // given (implicit) specialization of the enclosing class template, the // primary member template and its other partial specializations are still // considered for this specialization of the enclosing class template. - if (Template->isMemberSpecialization() && - !Partial->isMemberSpecialization()) + if (Template->getMostRecentDecl()->isMemberSpecialization() && + !Partial->getMostRecentDecl()->isMemberSpecialization()) continue; TemplateDeductionInfo Info(FailedCandidates.getLocation()); diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 6e1492f8cd447e..b63063813f1b56 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -3990,7 +3990,8 @@ bool Sema::usesPartialOrExplicitSpecialization( // given (implicit) specialization of the enclosing class template, the // primary member template and its other partial specializations are still // considered for this specialization of the enclosing class template. - if (CTD->isMemberSpecialization() && !CTPSD->isMemberSpecialization()) + if (CTD->getMostRecentDecl()->isMemberSpecialization() && + !CTPSD->getMostRecentDecl()->isMemberSpecialization()) continue; TemplateDeductionInfo Info(Loc); @@ -4037,8 +4038,7 @@ getPatternForClassTemplateSpecialization( SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs; Template->getPartialSpecializations(PartialSpecs); TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation); - for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) { - ClassTemplatePartialSpecializationDecl *Partial = PartialSpecs[I]; + for (ClassTemplatePartialSpecializationDecl *Partial : PartialSpecs) { // C++ [temp.spec.partial.member]p2: // If the primary member template is explicitly specialized for a given // (implicit) specialization of the enclosing class template, the @@ -4049,8 +4049,8 @@ getPatternForClassTemplateSpecialization( // primary member template and its other partial specializations are // still considered for this specialization of the enclosing class // template. - if (Template->isMemberSpecialization() && - !Partial->isMemberSpecialization()) + if (Template->getMostRecentDecl()->isMemberSpecialization() && + !Partial->getMostRecentDecl()->isMemberSpecialization()) continue; TemplateDeductionInfo Info(FailedCandidates.getLocation()); >From b8b0869d37b327df69a6be425407a279380ab8c3 Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski <sdkryst...@gmail.com> Date: Wed, 30 Oct 2024 09:51:40 -0400 Subject: [PATCH 3/4] [FOLD] add release note --- clang/docs/ReleaseNotes.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 6085352dfafe6b..1a179e63f902f3 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -574,6 +574,8 @@ Bug Fixes to C++ Support (#GH95854). - Fixed an assertion failure when evaluating an invalid expression in an array initializer. (#GH112140) - Fixed an assertion failure in range calculations for conditional throw expressions. (#GH111854) +- Clang now correctly ignores previous partial specializations of member templates explicitly specialized for + an implicitly instantiated class template specialization. (#GH51051) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ >From a3356a0a0fe36902896c69c82ca30e4deda238d1 Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski <sdkryst...@gmail.com> Date: Wed, 30 Oct 2024 10:01:34 -0400 Subject: [PATCH 4/4] [FOLD] add more tests --- .../temp.spec.partial.member/p2.cpp | 38 +++++++++++++------ 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/clang/test/CXX/temp/temp.decls/temp.spec.partial/temp.spec.partial.member/p2.cpp b/clang/test/CXX/temp/temp.decls/temp.spec.partial/temp.spec.partial.member/p2.cpp index 9a71da4bae37ca..0536cd23fd9adf 100644 --- a/clang/test/CXX/temp/temp.decls/temp.spec.partial/temp.spec.partial.member/p2.cpp +++ b/clang/test/CXX/temp/temp.decls/temp.spec.partial/temp.spec.partial.member/p2.cpp @@ -27,27 +27,43 @@ static_assert(A<short>::x<int*> == 1); template<> template<typename U> -struct A<long>::B { +struct A<int>::B { static constexpr int y = 2; }; template<> template<typename U> -struct A<long>::B<U&> { +struct A<int>::B<U&> { static constexpr int y = 3; }; template<> template<typename U> -constexpr int A<long>::x = 2; +struct A<long>::B<U&> { + static constexpr int y = 4; +}; + +template<> +template<typename U> +constexpr int A<int>::x = 2; template<> template<typename U> -constexpr int A<long>::x<U&> = 3; - -static_assert(A<long>::B<int>::y == 2); -static_assert(A<long>::B<int*>::y == 2); -static_assert(A<long>::B<int&>::y == 3); -static_assert(A<long>::x<int> == 2); -static_assert(A<long>::x<int*> == 2); -static_assert(A<long>::x<int&> == 3); +constexpr int A<int>::x<U&> = 3; + +template<> +template<typename U> +constexpr int A<long>::x<U&> = 4; + +static_assert(A<int>::B<int>::y == 2); +static_assert(A<int>::B<int*>::y == 2); +static_assert(A<int>::B<int&>::y == 3); +static_assert(A<int>::x<int> == 2); +static_assert(A<int>::x<int*> == 2); +static_assert(A<int>::x<int&> == 3); +static_assert(A<long>::B<int>::y == 0); +static_assert(A<long>::B<int*>::y == 1); +static_assert(A<long>::B<int&>::y == 4); +static_assert(A<long>::x<int> == 0); +static_assert(A<long>::x<int*> == 1); +static_assert(A<long>::x<int&> == 4); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits