Skip to content

Commit c76e470

Browse files
committed
[clang] fix P3310 overload resolution flag propagation
Class templates might be only instantiated when they are required to be complete, but checking the template args against the primary template is immediate. This result is cached so that later when the class is instantiated, checking against the primary template is not repeated. The 'MatchedPackOnParmToNonPackOnArg' flag is also produced upon checking against the primary template, so it needs to be cached in the specialziation as well. This fixes a bug which has not been in any release, so there are no release notes. Fixes #125290
1 parent 0caba6c commit c76e470

File tree

12 files changed

+87
-38
lines changed

12 files changed

+87
-38
lines changed

clang/include/clang/AST/DeclTemplate.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1841,15 +1841,21 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
18411841
LLVM_PREFERRED_TYPE(TemplateSpecializationKind)
18421842
unsigned SpecializationKind : 3;
18431843

1844+
/// When matching the primary template, have we matched any packs on the
1845+
/// parameter side, versus any non-packs on the argument side, in a context
1846+
/// where the opposite matching is also allowed?
1847+
bool MatchedPackOnParmToNonPackOnArg : 1;
1848+
18441849
protected:
18451850
ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, TagKind TK,
18461851
DeclContext *DC, SourceLocation StartLoc,
18471852
SourceLocation IdLoc,
18481853
ClassTemplateDecl *SpecializedTemplate,
18491854
ArrayRef<TemplateArgument> Args,
1855+
bool MatchedPackOnParmToNonPackOnArg,
18501856
ClassTemplateSpecializationDecl *PrevDecl);
18511857

1852-
explicit ClassTemplateSpecializationDecl(ASTContext &C, Kind DK);
1858+
ClassTemplateSpecializationDecl(ASTContext &C, Kind DK);
18531859

18541860
public:
18551861
friend class ASTDeclReader;
@@ -1859,7 +1865,7 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
18591865
Create(ASTContext &Context, TagKind TK, DeclContext *DC,
18601866
SourceLocation StartLoc, SourceLocation IdLoc,
18611867
ClassTemplateDecl *SpecializedTemplate,
1862-
ArrayRef<TemplateArgument> Args,
1868+
ArrayRef<TemplateArgument> Args, bool MatchedPackOnParmToNonPackOnArg,
18631869
ClassTemplateSpecializationDecl *PrevDecl);
18641870
static ClassTemplateSpecializationDecl *CreateDeserialized(ASTContext &C,
18651871
GlobalDeclID ID);
@@ -1930,6 +1936,10 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
19301936
SpecializationKind = TSK;
19311937
}
19321938

1939+
bool hasMatchedPackOnParmToNonPackOnArg() const {
1940+
return MatchedPackOnParmToNonPackOnArg;
1941+
}
1942+
19331943
/// Get the point of instantiation (if any), or null if none.
19341944
SourceLocation getPointOfInstantiation() const {
19351945
return PointOfInstantiation;

clang/lib/AST/ASTImporter.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6321,9 +6321,9 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
63216321
updateLookupTableForTemplateParameters(*ToTPList);
63226322
} else { // Not a partial specialization.
63236323
if (GetImportedOrCreateDecl(
6324-
D2, D, Importer.getToContext(), D->getTagKind(), DC,
6325-
*BeginLocOrErr, *IdLocOrErr, ClassTemplate, TemplateArgs,
6326-
PrevDecl))
6324+
D2, D, Importer.getToContext(), D->getTagKind(), DC, *BeginLocOrErr,
6325+
*IdLocOrErr, ClassTemplate, TemplateArgs,
6326+
D->hasMatchedPackOnParmToNonPackOnArg(), PrevDecl))
63276327
return D2;
63286328

63296329
// Update InsertPos, because preceding import calls may have invalidated

clang/lib/AST/DeclTemplate.cpp

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -957,18 +957,20 @@ FunctionTemplateSpecializationInfo *FunctionTemplateSpecializationInfo::Create(
957957
// ClassTemplateSpecializationDecl Implementation
958958
//===----------------------------------------------------------------------===//
959959

960-
ClassTemplateSpecializationDecl::
961-
ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, TagKind TK,
962-
DeclContext *DC, SourceLocation StartLoc,
963-
SourceLocation IdLoc,
964-
ClassTemplateDecl *SpecializedTemplate,
965-
ArrayRef<TemplateArgument> Args,
966-
ClassTemplateSpecializationDecl *PrevDecl)
960+
ClassTemplateSpecializationDecl::ClassTemplateSpecializationDecl(
961+
ASTContext &Context, Kind DK, TagKind TK, DeclContext *DC,
962+
SourceLocation StartLoc, SourceLocation IdLoc,
963+
ClassTemplateDecl *SpecializedTemplate, ArrayRef<TemplateArgument> Args,
964+
bool MatchedPackOnParmToNonPackOnArg,
965+
ClassTemplateSpecializationDecl *PrevDecl)
967966
: CXXRecordDecl(DK, TK, Context, DC, StartLoc, IdLoc,
968967
SpecializedTemplate->getIdentifier(), PrevDecl),
969-
SpecializedTemplate(SpecializedTemplate),
970-
TemplateArgs(TemplateArgumentList::CreateCopy(Context, Args)),
971-
SpecializationKind(TSK_Undeclared) {
968+
SpecializedTemplate(SpecializedTemplate),
969+
TemplateArgs(TemplateArgumentList::CreateCopy(Context, Args)),
970+
SpecializationKind(TSK_Undeclared),
971+
MatchedPackOnParmToNonPackOnArg(MatchedPackOnParmToNonPackOnArg) {
972+
assert(DK == Kind::ClassTemplateSpecialization ||
973+
MatchedPackOnParmToNonPackOnArg == false);
972974
}
973975

974976
ClassTemplateSpecializationDecl::ClassTemplateSpecializationDecl(ASTContext &C,
@@ -977,18 +979,14 @@ ClassTemplateSpecializationDecl::ClassTemplateSpecializationDecl(ASTContext &C,
977979
SourceLocation(), nullptr, nullptr),
978980
SpecializationKind(TSK_Undeclared) {}
979981

980-
ClassTemplateSpecializationDecl *
981-
ClassTemplateSpecializationDecl::Create(ASTContext &Context, TagKind TK,
982-
DeclContext *DC,
983-
SourceLocation StartLoc,
984-
SourceLocation IdLoc,
985-
ClassTemplateDecl *SpecializedTemplate,
986-
ArrayRef<TemplateArgument> Args,
987-
ClassTemplateSpecializationDecl *PrevDecl) {
988-
auto *Result =
989-
new (Context, DC) ClassTemplateSpecializationDecl(
990-
Context, ClassTemplateSpecialization, TK, DC, StartLoc, IdLoc,
991-
SpecializedTemplate, Args, PrevDecl);
982+
ClassTemplateSpecializationDecl *ClassTemplateSpecializationDecl::Create(
983+
ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc,
984+
SourceLocation IdLoc, ClassTemplateDecl *SpecializedTemplate,
985+
ArrayRef<TemplateArgument> Args, bool MatchedPackOnParmToNonPackOnArg,
986+
ClassTemplateSpecializationDecl *PrevDecl) {
987+
auto *Result = new (Context, DC) ClassTemplateSpecializationDecl(
988+
Context, ClassTemplateSpecialization, TK, DC, StartLoc, IdLoc,
989+
SpecializedTemplate, Args, MatchedPackOnParmToNonPackOnArg, PrevDecl);
992990
Result->setMayHaveOutOfDateDef(false);
993991

994992
// If the template decl is incomplete, copy the external lexical storage from
@@ -1175,7 +1173,10 @@ ClassTemplatePartialSpecializationDecl::ClassTemplatePartialSpecializationDecl(
11751173
ClassTemplatePartialSpecializationDecl *PrevDecl)
11761174
: ClassTemplateSpecializationDecl(
11771175
Context, ClassTemplatePartialSpecialization, TK, DC, StartLoc, IdLoc,
1178-
SpecializedTemplate, Args, PrevDecl),
1176+
// Tracking MatchedPackOnParmToNonPackOnArg for Partial
1177+
// Specializations is not needed.
1178+
SpecializedTemplate, Args, /*MatchedPackOnParmToNonPackOnArg=*/false,
1179+
PrevDecl),
11791180
TemplateParams(Params), InstantiatedFromMember(nullptr, false) {
11801181
if (AdoptTemplateParameterList(Params, this))
11811182
setInvalidDecl();

clang/lib/AST/TextNodeDumper.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2525,8 +2525,11 @@ void TextNodeDumper::VisitCXXRecordDecl(const CXXRecordDecl *D) {
25252525
OS << " instantiated_from";
25262526
dumpPointer(Instance);
25272527
}
2528-
if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D))
2528+
if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
25292529
dumpTemplateSpecializationKind(CTSD->getSpecializationKind());
2530+
if (CTSD->hasMatchedPackOnParmToNonPackOnArg())
2531+
OS << " strict_match";
2532+
}
25302533

25312534
dumpNestedNameSpecifier(D->getQualifier());
25322535

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3651,7 +3651,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
36513651
ClassTemplate->getDeclContext(),
36523652
ClassTemplate->getTemplatedDecl()->getBeginLoc(),
36533653
ClassTemplate->getLocation(), ClassTemplate, CTAI.CanonicalConverted,
3654-
nullptr);
3654+
CTAI.MatchedPackOnParmToNonPackOnArg, nullptr);
36553655
ClassTemplate->AddSpecialization(Decl, InsertPos);
36563656
if (ClassTemplate->isOutOfLine())
36573657
Decl->setLexicalDeclContext(ClassTemplate->getLexicalDeclContext());
@@ -8526,7 +8526,8 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
85268526
// this explicit specialization or friend declaration.
85278527
Specialization = ClassTemplateSpecializationDecl::Create(
85288528
Context, Kind, DC, KWLoc, TemplateNameLoc, ClassTemplate,
8529-
CTAI.CanonicalConverted, PrevDecl);
8529+
CTAI.CanonicalConverted, CTAI.MatchedPackOnParmToNonPackOnArg,
8530+
PrevDecl);
85308531
Specialization->setTemplateArgsAsWritten(TemplateArgs);
85318532
SetNestedNameSpecifier(*this, Specialization, SS);
85328533
if (TemplateParameterLists.size() > 0) {
@@ -9869,7 +9870,8 @@ DeclResult Sema::ActOnExplicitInstantiation(
98699870
// this explicit specialization.
98709871
Specialization = ClassTemplateSpecializationDecl::Create(
98719872
Context, Kind, ClassTemplate->getDeclContext(), KWLoc, TemplateNameLoc,
9872-
ClassTemplate, CTAI.CanonicalConverted, PrevDecl);
9873+
ClassTemplate, CTAI.CanonicalConverted,
9874+
CTAI.MatchedPackOnParmToNonPackOnArg, PrevDecl);
98739875
SetNestedNameSpecifier(*this, Specialization, SS);
98749876

98759877
// A MSInheritanceAttr attached to the previous declaration must be

clang/lib/Sema/SemaTemplateDeduction.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3341,8 +3341,6 @@ FinishTemplateArgumentDeduction(
33413341
return ConstraintsNotSatisfied
33423342
? TemplateDeductionResult::ConstraintsNotSatisfied
33433343
: TemplateDeductionResult::SubstitutionFailure;
3344-
if (InstCTAI.MatchedPackOnParmToNonPackOnArg)
3345-
Info.setMatchedPackOnParmToNonPackOnArg();
33463344

33473345
TemplateParameterList *TemplateParams = Template->getTemplateParameters();
33483346
for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) {

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4038,7 +4038,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
40384038
ClassTemplateSpecializationDecl::Create(
40394039
SemaRef.Context, D->getTagKind(), Owner, D->getBeginLoc(),
40404040
D->getLocation(), InstClassTemplate, CTAI.CanonicalConverted,
4041-
PrevDecl);
4041+
CTAI.MatchedPackOnParmToNonPackOnArg, PrevDecl);
40424042
InstD->setTemplateArgsAsWritten(InstTemplateArgs);
40434043

40444044
// Add this partial specialization to the set of class template partial

clang/lib/Sema/SemaType.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9397,7 +9397,8 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
93979397
runWithSufficientStackSpace(Loc, [&] {
93989398
Diagnosed = InstantiateClassTemplateSpecialization(
93999399
Loc, ClassTemplateSpec, TSK_ImplicitInstantiation,
9400-
/*Complain=*/Diagnoser);
9400+
/*Complain=*/Diagnoser,
9401+
ClassTemplateSpec->hasMatchedPackOnParmToNonPackOnArg());
94019402
});
94029403
Instantiated = true;
94039404
}

clang/lib/Serialization/ASTReaderDecl.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2532,6 +2532,7 @@ RedeclarableResult ASTDeclReader::VisitClassTemplateSpecializationDeclImpl(
25322532
D->TemplateArgs = TemplateArgumentList::CreateCopy(C, TemplArgs);
25332533
D->PointOfInstantiation = readSourceLocation();
25342534
D->SpecializationKind = (TemplateSpecializationKind)Record.readInt();
2535+
D->MatchedPackOnParmToNonPackOnArg = Record.readBool();
25352536

25362537
bool writtenAsCanonicalDecl = Record.readInt();
25372538
if (writtenAsCanonicalDecl) {

clang/lib/Serialization/ASTWriterDecl.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1843,6 +1843,7 @@ void ASTDeclWriter::VisitClassTemplateSpecializationDecl(
18431843
Record.AddTemplateArgumentList(&D->getTemplateArgs());
18441844
Record.AddSourceLocation(D->getPointOfInstantiation());
18451845
Record.push_back(D->getSpecializationKind());
1846+
Record.push_back(D->hasMatchedPackOnParmToNonPackOnArg());
18461847
Record.push_back(D->isCanonicalDecl());
18471848

18481849
if (D->isCanonicalDecl()) {

clang/test/AST/ast-dump-templates.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1-
// RUN: %clang_cc1 -std=c++1z -ast-print %s > %t
1+
// RUN: %clang_cc1 -std=c++17 -ast-print %s > %t
22
// RUN: FileCheck < %t %s -check-prefix=CHECK1
33
// RUN: FileCheck < %t %s -check-prefix=CHECK2
4-
// RUN: %clang_cc1 -std=c++1z -ast-dump %s | FileCheck --check-prefix=DUMP %s
4+
// RUN: %clang_cc1 -std=c++17 -ast-dump %s | FileCheck --check-prefix=DUMP %s
5+
6+
// Test with serialization:
7+
// RUN: %clang_cc1 -std=c++17 -emit-pch -o %t %s
8+
// RUN: %clang_cc1 -x c++ -std=c++17 -include-pch %t \
9+
// RUN: -ast-dump-all /dev/null \
10+
// RUN: | sed -e "s/ <undeserialized declarations>//" -e "s/ imported//" \
11+
// RUN: | FileCheck --strict-whitespace --check-prefix=DUMP %s
512

613
template <int X, typename Y, int Z = 5>
714
struct foo {
@@ -118,3 +125,11 @@ void func() {
118125
// DUMP-NEXT: `-TemplateTypeParm {{.*}} 'Key'
119126
}
120127
}
128+
129+
namespace test7 {
130+
template <template<class> class TT> struct A {};
131+
template <class...> class B {};
132+
template struct A<B>;
133+
// DUMP-LABEL: NamespaceDecl {{.*}} test7{{$}}
134+
// DUMP: ClassTemplateSpecializationDecl {{.*}} struct A definition explicit_instantiation_definition strict_match{{$}}
135+
} // namespce test7

clang/test/SemaTemplate/cwg2398.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,23 @@ namespace regression2 {
585585
template <typename, int> struct Matrix;
586586
template struct D<Matrix<double, 3>>;
587587
} // namespace regression2
588+
namespace regression3 {
589+
struct None {};
590+
template<class T> struct Node { using type = T; };
591+
592+
template <template<class> class TT, class T>
593+
struct A {
594+
static_assert(!__is_same(T, None));
595+
using type2 = typename A<TT, typename T::type>::type2;
596+
};
597+
598+
template <template<class> class TT> struct A<TT, None> {
599+
using type2 = void;
600+
};
601+
602+
template <class...> class B {};
603+
template struct A<B, Node<None>>;
604+
} // namespace regression3
588605

589606
namespace nttp_auto {
590607
namespace t1 {

0 commit comments

Comments
 (0)