Skip to content

Commit 7542bda

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

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
@@ -3978,11 +3978,23 @@ bool Sema::usesPartialOrExplicitSpecialization(
39783978
return true;
39793979

39803980
SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
3981-
ClassTemplateSpec->getSpecializedTemplate()
3982-
->getPartialSpecializations(PartialSpecs);
3983-
for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) {
3981+
ClassTemplateDecl *CTD = ClassTemplateSpec->getSpecializedTemplate();
3982+
CTD->getPartialSpecializations(PartialSpecs);
3983+
for (ClassTemplatePartialSpecializationDecl *CTPSD : PartialSpecs) {
3984+
// C++ [temp.spec.partial.member]p2:
3985+
// If the primary member template is explicitly specialized for a given
3986+
// (implicit) specialization of the enclosing class template, the partial
3987+
// specializations of the member template are ignored for this
3988+
// specialization of the enclosing class template. If a partial
3989+
// specialization of the member template is explicitly specialized for a
3990+
// given (implicit) specialization of the enclosing class template, the
3991+
// primary member template and its other partial specializations are still
3992+
// considered for this specialization of the enclosing class template.
3993+
if (CTD->isMemberSpecialization() && !CTPSD->isMemberSpecialization())
3994+
continue;
3995+
39843996
TemplateDeductionInfo Info(Loc);
3985-
if (DeduceTemplateArguments(PartialSpecs[I],
3997+
if (DeduceTemplateArguments(CTPSD,
39863998
ClassTemplateSpec->getTemplateArgs().asArray(),
39873999
Info) == TemplateDeductionResult::Success)
39884000
return true;
@@ -4027,6 +4039,20 @@ getPatternForClassTemplateSpecialization(
40274039
TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation);
40284040
for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) {
40294041
ClassTemplatePartialSpecializationDecl *Partial = PartialSpecs[I];
4042+
// C++ [temp.spec.partial.member]p2:
4043+
// If the primary member template is explicitly specialized for a given
4044+
// (implicit) specialization of the enclosing class template, the
4045+
// partial specializations of the member template are ignored for this
4046+
// specialization of the enclosing class template. If a partial
4047+
// specialization of the member template is explicitly specialized for a
4048+
// given (implicit) specialization of the enclosing class template, the
4049+
// primary member template and its other partial specializations are
4050+
// still considered for this specialization of the enclosing class
4051+
// template.
4052+
if (Template->isMemberSpecialization() &&
4053+
!Partial->isMemberSpecialization())
4054+
continue;
4055+
40304056
TemplateDeductionInfo Info(FailedCandidates.getLocation());
40314057
if (TemplateDeductionResult Result = S.DeduceTemplateArguments(
40324058
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)