Skip to content

Commit 79912b6

Browse files
committed
[Clang][Sema] Ignore previous partial specializations of member class templates explicitly specialized for a implicitly instantiated class template specialization
1 parent a18826d commit 79912b6

File tree

3 files changed

+96
-4
lines changed

3 files changed

+96
-4
lines changed

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4383,6 +4383,19 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
43834383

43844384
for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) {
43854385
VarTemplatePartialSpecializationDecl *Partial = PartialSpecs[I];
4386+
// C++ [temp.spec.partial.member]p2:
4387+
// If the primary member template is explicitly specialized for a given
4388+
// (implicit) specialization of the enclosing class template, the partial
4389+
// specializations of the member template are ignored for this
4390+
// specialization of the enclosing class template. If a partial
4391+
// specialization of the member template is explicitly specialized for a
4392+
// given (implicit) specialization of the enclosing class template, the
4393+
// primary member template and its other partial specializations are still
4394+
// considered for this specialization of the enclosing class template.
4395+
if (Template->isMemberSpecialization() &&
4396+
!Partial->isMemberSpecialization())
4397+
continue;
4398+
43864399
TemplateDeductionInfo Info(FailedCandidates.getLocation());
43874400

43884401
if (TemplateDeductionResult Result =

clang/lib/Sema/SemaTemplateInstantiate.cpp

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3979,11 +3979,23 @@ bool Sema::usesPartialOrExplicitSpecialization(
39793979
return true;
39803980

39813981
SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
3982-
ClassTemplateSpec->getSpecializedTemplate()
3983-
->getPartialSpecializations(PartialSpecs);
3984-
for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) {
3982+
ClassTemplateDecl *CTD = ClassTemplateSpec->getSpecializedTemplate();
3983+
CTD->getPartialSpecializations(PartialSpecs);
3984+
for (ClassTemplatePartialSpecializationDecl *CTPSD : PartialSpecs) {
3985+
// C++ [temp.spec.partial.member]p2:
3986+
// If the primary member template is explicitly specialized for a given
3987+
// (implicit) specialization of the enclosing class template, the partial
3988+
// specializations of the member template are ignored for this
3989+
// specialization of the enclosing class template. If a partial
3990+
// specialization of the member template is explicitly specialized for a
3991+
// given (implicit) specialization of the enclosing class template, the
3992+
// primary member template and its other partial specializations are still
3993+
// considered for this specialization of the enclosing class template.
3994+
if (CTD->isMemberSpecialization() && !CTPSD->isMemberSpecialization())
3995+
continue;
3996+
39853997
TemplateDeductionInfo Info(Loc);
3986-
if (DeduceTemplateArguments(PartialSpecs[I],
3998+
if (DeduceTemplateArguments(CTPSD,
39873999
ClassTemplateSpec->getTemplateArgs().asArray(),
39884000
Info) == TemplateDeductionResult::Success)
39894001
return true;
@@ -4028,6 +4040,20 @@ getPatternForClassTemplateSpecialization(
40284040
TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation);
40294041
for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) {
40304042
ClassTemplatePartialSpecializationDecl *Partial = PartialSpecs[I];
4043+
// C++ [temp.spec.partial.member]p2:
4044+
// If the primary member template is explicitly specialized for a given
4045+
// (implicit) specialization of the enclosing class template, the
4046+
// partial specializations of the member template are ignored for this
4047+
// specialization of the enclosing class template. If a partial
4048+
// specialization of the member template is explicitly specialized for a
4049+
// given (implicit) specialization of the enclosing class template, the
4050+
// primary member template and its other partial specializations are
4051+
// still considered for this specialization of the enclosing class
4052+
// template.
4053+
if (Template->isMemberSpecialization() &&
4054+
!Partial->isMemberSpecialization())
4055+
continue;
4056+
40314057
TemplateDeductionInfo Info(FailedCandidates.getLocation());
40324058
if (TemplateDeductionResult Result = S.DeduceTemplateArguments(
40334059
Partial, ClassTemplateSpec->getTemplateArgs().asArray(), Info);
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
2+
// expected-no-diagnostics
3+
4+
template<typename T>
5+
struct A {
6+
template<typename U>
7+
struct B {
8+
static constexpr int y = 0;
9+
};
10+
11+
template<typename U>
12+
struct B<U*> {
13+
static constexpr int y = 1;
14+
};
15+
16+
template<typename U>
17+
static constexpr int x = 0;
18+
19+
template<typename U>
20+
static constexpr int x<U*> = 1;
21+
};
22+
23+
static_assert(A<short>::B<int>::y == 0);
24+
static_assert(A<short>::B<int*>::y == 1);
25+
static_assert(A<short>::x<int> == 0);
26+
static_assert(A<short>::x<int*> == 1);
27+
28+
template<>
29+
template<typename U>
30+
struct A<long>::B {
31+
static constexpr int y = 2;
32+
};
33+
34+
template<>
35+
template<typename U>
36+
struct A<long>::B<U&> {
37+
static constexpr int y = 3;
38+
};
39+
40+
template<>
41+
template<typename U>
42+
constexpr int A<long>::x = 2;
43+
44+
template<>
45+
template<typename U>
46+
constexpr int A<long>::x<U&> = 3;
47+
48+
static_assert(A<long>::B<int>::y == 2);
49+
static_assert(A<long>::B<int*>::y == 2);
50+
static_assert(A<long>::B<int&>::y == 3);
51+
static_assert(A<long>::x<int> == 2);
52+
static_assert(A<long>::x<int*> == 2);
53+
static_assert(A<long>::x<int&> == 3);

0 commit comments

Comments
 (0)