[clang] Revert "Reapply "[Clang][Sema] Refactor collection of multi-level template argument lists (#106585)" (#111173)" (PR #111766)
Krystian Stasiowski via cfe-commits
cfe-commits at lists.llvm.org
Wed Oct 9 14:49:16 PDT 2024
https://github.com/sdkrystian created https://github.com/llvm/llvm-project/pull/111766
This reverts commit 4da8ac34f76e707ab94380b94f616457cfd2cb83.
>From 88925f844c22b9c8b4f0bfce1ebc467d24a8854d Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Wed, 9 Oct 2024 17:48:37 -0400
Subject: [PATCH] Revert "Reapply "[Clang][Sema] Refactor collection of
multi-level template argument lists (#106585)" (#111173)"
This reverts commit 4da8ac34f76e707ab94380b94f616457cfd2cb83.
---
clang/docs/ReleaseNotes.rst | 3 -
clang/include/clang/AST/DeclTemplate.h | 66 +-
clang/include/clang/Sema/Sema.h | 25 +-
clang/lib/AST/Decl.cpp | 49 +-
clang/lib/AST/DeclCXX.cpp | 20 +-
clang/lib/AST/DeclTemplate.cpp | 30 +-
clang/lib/Sema/SemaConcept.cpp | 29 +-
clang/lib/Sema/SemaDecl.cpp | 31 +-
clang/lib/Sema/SemaDeclCXX.cpp | 4 +-
clang/lib/Sema/SemaTemplate.cpp | 179 +++--
clang/lib/Sema/SemaTemplateDeduction.cpp | 33 +-
clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 45 +-
clang/lib/Sema/SemaTemplateInstantiate.cpp | 752 +++++++++---------
.../lib/Sema/SemaTemplateInstantiateDecl.cpp | 46 +-
clang/lib/Serialization/ASTReader.cpp | 3 +-
clang/lib/Serialization/ASTReaderDecl.cpp | 18 +-
clang/lib/Serialization/ASTWriterDecl.cpp | 17 +-
.../temp/temp.constr/temp.constr.decl/p4.cpp | 175 ----
.../CXX/temp/temp.spec/temp.expl.spec/p7.cpp | 178 -----
clang/test/Modules/cxx-templates.cpp | 4 +-
20 files changed, 702 insertions(+), 1005 deletions(-)
delete mode 100644 clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp
delete mode 100644 clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 29b9fe07f545f9..16e6a230ef428e 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -477,9 +477,6 @@ Bug Fixes to C++ Support
in certain friend declarations. (#GH93099)
- Clang now instantiates the correct lambda call operator when a lambda's class type is
merged across modules. (#GH110401)
-- Clang now uses the correct set of template argument lists when comparing the constraints of
- out-of-line definitions and member templates explicitly specialized for a given implicit instantiation of
- a class template. (#GH102320)
- Fix a crash when parsing a pseudo destructor involving an invalid type. (#GH111460)
Bug Fixes to AST Handling
diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index 05739f39d2a496..687715a22e9fd3 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -781,11 +781,15 @@ class RedeclarableTemplateDecl : public TemplateDecl,
EntryType *Entry, void *InsertPos);
struct CommonBase {
- CommonBase() {}
+ CommonBase() : InstantiatedFromMember(nullptr, false) {}
/// The template from which this was most
/// directly instantiated (or null).
- RedeclarableTemplateDecl *InstantiatedFromMember = nullptr;
+ ///
+ /// The boolean value indicates whether this template
+ /// was explicitly specialized.
+ llvm::PointerIntPair<RedeclarableTemplateDecl*, 1, bool>
+ InstantiatedFromMember;
/// If non-null, points to an array of specializations (including
/// partial specializations) known only by their external declaration IDs.
@@ -805,19 +809,14 @@ class RedeclarableTemplateDecl : public TemplateDecl,
};
/// Pointer to the common data shared by all declarations of this
- /// template, and a flag indicating if the template is a member
- /// specialization.
- mutable llvm::PointerIntPair<CommonBase *, 1, bool> Common;
-
- CommonBase *getCommonPtrInternal() const { return Common.getPointer(); }
+ /// template.
+ mutable CommonBase *Common = nullptr;
/// Retrieves the "common" pointer shared by all (re-)declarations of
/// the same template. Calling this routine may implicitly allocate memory
/// for the common pointer.
CommonBase *getCommonPtr() const;
- void setCommonPtr(CommonBase *C) const { Common.setPointer(C); }
-
virtual CommonBase *newCommon(ASTContext &C) const = 0;
// Construct a template decl with name, parameters, and templated element.
@@ -858,12 +857,15 @@ class RedeclarableTemplateDecl : public TemplateDecl,
/// template<> template<typename T>
/// struct X<int>::Inner { /* ... */ };
/// \endcode
- bool isMemberSpecialization() const { return Common.getInt(); }
+ bool isMemberSpecialization() const {
+ return getCommonPtr()->InstantiatedFromMember.getInt();
+ }
/// Note that this member template is a specialization.
void setMemberSpecialization() {
- assert(!isMemberSpecialization() && "already a member specialization");
- Common.setInt(true);
+ assert(getCommonPtr()->InstantiatedFromMember.getPointer() &&
+ "Only member templates can be member template specializations");
+ getCommonPtr()->InstantiatedFromMember.setInt(true);
}
/// Retrieve the member template from which this template was
@@ -903,12 +905,12 @@ class RedeclarableTemplateDecl : public TemplateDecl,
/// void X<T>::f(T, U);
/// \endcode
RedeclarableTemplateDecl *getInstantiatedFromMemberTemplate() const {
- return getCommonPtr()->InstantiatedFromMember;
+ return getCommonPtr()->InstantiatedFromMember.getPointer();
}
void setInstantiatedFromMemberTemplate(RedeclarableTemplateDecl *TD) {
- assert(!getCommonPtr()->InstantiatedFromMember);
- getCommonPtr()->InstantiatedFromMember = TD;
+ assert(!getCommonPtr()->InstantiatedFromMember.getPointer());
+ getCommonPtr()->InstantiatedFromMember.setPointer(TD);
}
/// Retrieve the "injected" template arguments that correspond to the
@@ -1987,8 +1989,6 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
/// template arguments have been deduced.
void setInstantiationOf(ClassTemplatePartialSpecializationDecl *PartialSpec,
const TemplateArgumentList *TemplateArgs) {
- assert(!isa<ClassTemplatePartialSpecializationDecl>(this) &&
- "A partial specialization cannot be instantiated from a template");
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() &&
"Already set to a class template partial specialization!");
auto *PS = new (getASTContext()) SpecializedPartialSpecialization();
@@ -2000,8 +2000,6 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
/// Note that this class template specialization is an instantiation
/// of the given class template.
void setInstantiationOf(ClassTemplateDecl *TemplDecl) {
- assert(!isa<ClassTemplatePartialSpecializationDecl>(this) &&
- "A partial specialization cannot be instantiated from a template");
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() &&
"Previously set to a class template partial specialization!");
SpecializedTemplate = TemplDecl;
@@ -2189,11 +2187,18 @@ class ClassTemplatePartialSpecializationDecl
/// struct X<int>::Inner<T*> { /* ... */ };
/// \endcode
bool isMemberSpecialization() const {
- return InstantiatedFromMember.getInt();
+ const auto *First =
+ cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
+ return First->InstantiatedFromMember.getInt();
}
/// Note that this member template is a specialization.
- void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); }
+ void setMemberSpecialization() {
+ auto *First = cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
+ assert(First->InstantiatedFromMember.getPointer() &&
+ "Only member templates can be member template specializations");
+ return First->InstantiatedFromMember.setInt(true);
+ }
/// Retrieves the injected specialization type for this partial
/// specialization. This is not the same as the type-decl-type for
@@ -2263,6 +2268,10 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr());
}
+ void setCommonPtr(Common *C) {
+ RedeclarableTemplateDecl::Common = C;
+ }
+
public:
friend class ASTDeclReader;
@@ -2745,8 +2754,6 @@ class VarTemplateSpecializationDecl : public VarDecl,
/// template arguments have been deduced.
void setInstantiationOf(VarTemplatePartialSpecializationDecl *PartialSpec,
const TemplateArgumentList *TemplateArgs) {
- assert(!isa<VarTemplatePartialSpecializationDecl>(this) &&
- "A partial specialization cannot be instantiated from a template");
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization *>() &&
"Already set to a variable template partial specialization!");
auto *PS = new (getASTContext()) SpecializedPartialSpecialization();
@@ -2758,8 +2765,6 @@ class VarTemplateSpecializationDecl : public VarDecl,
/// Note that this variable template specialization is an instantiation
/// of the given variable template.
void setInstantiationOf(VarTemplateDecl *TemplDecl) {
- assert(!isa<VarTemplatePartialSpecializationDecl>(this) &&
- "A partial specialization cannot be instantiated from a template");
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization *>() &&
"Previously set to a variable template partial specialization!");
SpecializedTemplate = TemplDecl;
@@ -2944,11 +2949,18 @@ class VarTemplatePartialSpecializationDecl
/// U* X<int>::Inner<T*> = (T*)(0) + 1;
/// \endcode
bool isMemberSpecialization() const {
- return InstantiatedFromMember.getInt();
+ const auto *First =
+ cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
+ return First->InstantiatedFromMember.getInt();
}
/// Note that this member template is a specialization.
- void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); }
+ void setMemberSpecialization() {
+ auto *First = cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
+ assert(First->InstantiatedFromMember.getPointer() &&
+ "Only member templates can be member template specializations");
+ return First->InstantiatedFromMember.setInt(true);
+ }
SourceRange getSourceRange() const override LLVM_READONLY;
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 67a6dbeb520a89..51f38a90f3ea05 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11325,9 +11325,9 @@ class Sema final : public SemaBase {
CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc,
const ParsedAttributesView &Attr, TemplateParameterList *TemplateParams,
AccessSpecifier AS, SourceLocation ModulePrivateLoc,
- SourceLocation FriendLoc,
- ArrayRef<TemplateParameterList *> OuterTemplateParamLists,
- bool IsMemberSpecialization, SkipBodyInfo *SkipBody = nullptr);
+ SourceLocation FriendLoc, unsigned NumOuterTemplateParamLists,
+ TemplateParameterList **OuterTemplateParamLists,
+ SkipBodyInfo *SkipBody = nullptr);
/// Translates template arguments as provided by the parser
/// into template arguments used by semantic analysis.
@@ -11366,8 +11366,7 @@ class Sema final : public SemaBase {
DeclResult ActOnVarTemplateSpecialization(
Scope *S, Declarator &D, TypeSourceInfo *DI, LookupResult &Previous,
SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams,
- StorageClass SC, bool IsPartialSpecialization,
- bool IsMemberSpecialization);
+ StorageClass SC, bool IsPartialSpecialization);
/// Get the specialization of the given variable template corresponding to
/// the specified argument list, or a null-but-valid result if the arguments
@@ -13008,14 +13007,28 @@ class Sema final : public SemaBase {
/// dealing with a specialization. This is only relevant for function
/// template specializations.
///
+ /// \param Pattern If non-NULL, indicates the pattern from which we will be
+ /// instantiating the definition of the given declaration, \p ND. This is
+ /// used to determine the proper set of template instantiation arguments for
+ /// friend function template specializations.
+ ///
/// \param ForConstraintInstantiation when collecting arguments,
/// ForConstraintInstantiation indicates we should continue looking when
/// encountering a lambda generic call operator, and continue looking for
/// arguments on an enclosing class template.
+ ///
+ /// \param SkipForSpecialization when specified, any template specializations
+ /// in a traversal would be ignored.
+ /// \param ForDefaultArgumentSubstitution indicates we should continue looking
+ /// when encountering a specialized member function template, rather than
+ /// returning immediately.
MultiLevelTemplateArgumentList getTemplateInstantiationArgs(
const NamedDecl *D, const DeclContext *DC = nullptr, bool Final = false,
std::optional<ArrayRef<TemplateArgument>> Innermost = std::nullopt,
- bool RelativeToPrimary = false, bool ForConstraintInstantiation = false);
+ bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr,
+ bool ForConstraintInstantiation = false,
+ bool SkipForSpecialization = false,
+ bool ForDefaultArgumentSubstitution = false);
/// RAII object to handle the state changes required to synthesize
/// a function body.
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 58d11a0312c505..84ef9f74582ef6 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -2696,27 +2696,21 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const {
if (isTemplateInstantiation(VDTemplSpec->getTemplateSpecializationKind())) {
auto From = VDTemplSpec->getInstantiatedFrom();
if (auto *VTD = From.dyn_cast<VarTemplateDecl *>()) {
- while (true) {
- VTD = VTD->getMostRecentDecl();
- if (VTD->isMemberSpecialization())
- break;
- if (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate())
- VTD = NewVTD;
- else
+ while (!VTD->isMemberSpecialization()) {
+ auto *NewVTD = VTD->getInstantiatedFromMemberTemplate();
+ if (!NewVTD)
break;
+ VTD = NewVTD;
}
return getDefinitionOrSelf(VTD->getTemplatedDecl());
}
if (auto *VTPSD =
From.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
- while (true) {
- VTPSD = VTPSD->getMostRecentDecl();
- if (VTPSD->isMemberSpecialization())
- break;
- if (auto *NewVTPSD = VTPSD->getInstantiatedFromMember())
- VTPSD = NewVTPSD;
- else
+ while (!VTPSD->isMemberSpecialization()) {
+ auto *NewVTPSD = VTPSD->getInstantiatedFromMember();
+ if (!NewVTPSD)
break;
+ VTPSD = NewVTPSD;
}
return getDefinitionOrSelf<VarDecl>(VTPSD);
}
@@ -2725,17 +2719,15 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const {
// If this is the pattern of a variable template, find where it was
// instantiated from. FIXME: Is this necessary?
- if (VarTemplateDecl *VTD = VD->getDescribedVarTemplate()) {
- while (true) {
- VTD = VTD->getMostRecentDecl();
- if (VTD->isMemberSpecialization())
- break;
- if (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate())
- VTD = NewVTD;
- else
+ if (VarTemplateDecl *VarTemplate = VD->getDescribedVarTemplate()) {
+ while (!VarTemplate->isMemberSpecialization()) {
+ auto *NewVT = VarTemplate->getInstantiatedFromMemberTemplate();
+ if (!NewVT)
break;
+ VarTemplate = NewVT;
}
- return getDefinitionOrSelf(VTD->getTemplatedDecl());
+
+ return getDefinitionOrSelf(VarTemplate->getTemplatedDecl());
}
if (VD == this)
@@ -4150,14 +4142,11 @@ FunctionDecl::getTemplateInstantiationPattern(bool ForDefinition) const {
if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) {
// If we hit a point where the user provided a specialization of this
// template, we're done looking.
- while (true) {
- Primary = Primary->getMostRecentDecl();
- if (ForDefinition && Primary->isMemberSpecialization())
- break;
- if (auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate())
- Primary = NewPrimary;
- else
+ while (!ForDefinition || !Primary->isMemberSpecialization()) {
+ auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate();
+ if (!NewPrimary)
break;
+ Primary = NewPrimary;
}
return getDefinitionOrSelf(Primary->getTemplatedDecl());
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index cfc7a9a218f251..1364ccc745ba01 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -2023,27 +2023,19 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const {
if (auto *TD = dyn_cast<ClassTemplateSpecializationDecl>(this)) {
auto From = TD->getInstantiatedFrom();
if (auto *CTD = From.dyn_cast<ClassTemplateDecl *>()) {
- while (true) {
- CTD = CTD->getMostRecentDecl();
- if (CTD->isMemberSpecialization())
- break;
- if (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate())
- CTD = NewCTD;
- else
+ while (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) {
+ if (NewCTD->isMemberSpecialization())
break;
+ CTD = NewCTD;
}
return GetDefinitionOrSelf(CTD->getTemplatedDecl());
}
if (auto *CTPSD =
From.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
- while (true) {
- CTPSD = CTPSD->getMostRecentDecl();
- if (CTPSD->isMemberSpecialization())
- break;
- if (auto *NewCTPSD = CTPSD->getInstantiatedFromMemberTemplate())
- CTPSD = NewCTPSD;
- else
+ while (auto *NewCTPSD = CTPSD->getInstantiatedFromMember()) {
+ if (NewCTPSD->isMemberSpecialization())
break;
+ CTPSD = NewCTPSD;
}
return GetDefinitionOrSelf(CTPSD);
}
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index d9b67b7bedf5a5..6fe817c5ef1c6b 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -309,16 +309,16 @@ bool TemplateDecl::isTypeAlias() const {
void RedeclarableTemplateDecl::anchor() {}
RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() const {
- if (CommonBase *C = getCommonPtrInternal())
- return C;
+ if (Common)
+ return Common;
// Walk the previous-declaration chain until we either find a declaration
// with a common pointer or we run out of previous declarations.
SmallVector<const RedeclarableTemplateDecl *, 2> PrevDecls;
for (const RedeclarableTemplateDecl *Prev = getPreviousDecl(); Prev;
Prev = Prev->getPreviousDecl()) {
- if (CommonBase *C = Prev->getCommonPtrInternal()) {
- setCommonPtr(C);
+ if (Prev->Common) {
+ Common = Prev->Common;
break;
}
@@ -326,18 +326,18 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() c
}
// If we never found a common pointer, allocate one now.
- if (!getCommonPtrInternal()) {
+ if (!Common) {
// FIXME: If any of the declarations is from an AST file, we probably
// need an update record to add the common data.
- setCommonPtr(newCommon(getASTContext()));
+ Common = newCommon(getASTContext());
}
// Update any previous declarations we saw with the common pointer.
for (const RedeclarableTemplateDecl *Prev : PrevDecls)
- Prev->setCommonPtr(getCommonPtrInternal());
+ Prev->Common = Common;
- return getCommonPtrInternal();
+ return Common;
}
void RedeclarableTemplateDecl::loadLazySpecializationsImpl() const {
@@ -463,17 +463,19 @@ void FunctionTemplateDecl::addSpecialization(
}
void FunctionTemplateDecl::mergePrevDecl(FunctionTemplateDecl *Prev) {
+ using Base = RedeclarableTemplateDecl;
+
// If we haven't created a common pointer yet, then it can just be created
// with the usual method.
- if (!getCommonPtrInternal())
+ if (!Base::Common)
return;
- Common *ThisCommon = static_cast<Common *>(getCommonPtrInternal());
+ Common *ThisCommon = static_cast<Common *>(Base::Common);
Common *PrevCommon = nullptr;
SmallVector<FunctionTemplateDecl *, 8> PreviousDecls;
for (; Prev; Prev = Prev->getPreviousDecl()) {
- if (CommonBase *C = Prev->getCommonPtrInternal()) {
- PrevCommon = static_cast<Common *>(C);
+ if (Prev->Base::Common) {
+ PrevCommon = static_cast<Common *>(Prev->Base::Common);
break;
}
PreviousDecls.push_back(Prev);
@@ -483,7 +485,7 @@ void FunctionTemplateDecl::mergePrevDecl(FunctionTemplateDecl *Prev) {
// use this common pointer.
if (!PrevCommon) {
for (auto *D : PreviousDecls)
- D->setCommonPtr(ThisCommon);
+ D->Base::Common = ThisCommon;
return;
}
@@ -491,7 +493,7 @@ void FunctionTemplateDecl::mergePrevDecl(FunctionTemplateDecl *Prev) {
assert(ThisCommon->Specializations.size() == 0 &&
"Can't merge incompatible declarations!");
- setCommonPtr(PrevCommon);
+ Base::Common = PrevCommon;
}
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index e36ee062213716..998a148a7d24a1 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -585,8 +585,8 @@ static bool CheckConstraintSatisfaction(
ArrayRef<TemplateArgument> TemplateArgs =
TemplateArgsLists.getNumSubstitutedLevels() > 0
- ? TemplateArgsLists.getInnermost()
- : ArrayRef<TemplateArgument>{};
+ ? TemplateArgsLists.getOutermost()
+ : ArrayRef<TemplateArgument> {};
Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(),
Sema::InstantiatingTemplate::ConstraintsCheck{},
const_cast<NamedDecl *>(Template), TemplateArgs, TemplateIDRange);
@@ -834,6 +834,7 @@ Sema::SetupConstraintCheckingTemplateArgumentsAndScope(
getTemplateInstantiationArgs(FD, FD->getLexicalDeclContext(),
/*Final=*/false, /*Innermost=*/std::nullopt,
/*RelativeToPrimary=*/true,
+ /*Pattern=*/nullptr,
/*ForConstraintInstantiation=*/true);
if (SetupConstraintScope(FD, TemplateArgs, MLTAL, Scope))
return std::nullopt;
@@ -909,13 +910,15 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
// Figure out the to-translation-unit depth for this function declaration for
// the purpose of seeing if they differ by constraints. This isn't the same as
// getTemplateDepth, because it includes already instantiated parents.
-static unsigned CalculateTemplateDepthForConstraints(Sema &S,
- const NamedDecl *ND) {
+static unsigned
+CalculateTemplateDepthForConstraints(Sema &S, const NamedDecl *ND,
+ bool SkipForSpecialization = false) {
MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
ND, ND->getLexicalDeclContext(), /*Final=*/false,
/*Innermost=*/std::nullopt,
/*RelativeToPrimary=*/true,
- /*ForConstraintInstantiation=*/true);
+ /*Pattern=*/nullptr,
+ /*ForConstraintInstantiation=*/true, SkipForSpecialization);
return MLTAL.getNumLevels();
}
@@ -954,7 +957,8 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
DeclInfo.getDecl(), DeclInfo.getLexicalDeclContext(), /*Final=*/false,
/*Innermost=*/std::nullopt,
/*RelativeToPrimary=*/true,
- /*ForConstraintInstantiation=*/true);
+ /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true,
+ /*SkipForSpecialization*/ false);
if (MLTAL.getNumSubstitutedLevels() == 0)
return ConstrExpr;
@@ -1064,16 +1068,16 @@ bool Sema::AreConstraintExpressionsEqual(const NamedDecl *Old,
bool Sema::FriendConstraintsDependOnEnclosingTemplate(const FunctionDecl *FD) {
assert(FD->getFriendObjectKind() && "Must be a friend!");
- FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate();
// The logic for non-templates is handled in ASTContext::isSameEntity, so we
// don't have to bother checking 'DependsOnEnclosingTemplate' for a
// non-function-template.
- assert(FTD && "Non-function templates don't need to be checked");
+ assert(FD->getDescribedFunctionTemplate() &&
+ "Non-function templates don't need to be checked");
SmallVector<const Expr *, 3> ACs;
- FTD->getAssociatedConstraints(ACs);
+ FD->getDescribedFunctionTemplate()->getAssociatedConstraints(ACs);
- unsigned OldTemplateDepth = FTD->getTemplateParameters()->getDepth();
+ unsigned OldTemplateDepth = CalculateTemplateDepthForConstraints(*this, FD);
for (const Expr *Constraint : ACs)
if (ConstraintExpressionDependsOnEnclosingTemplate(FD, OldTemplateDepth,
Constraint))
@@ -1520,6 +1524,7 @@ static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
CSE->getNamedConcept(), CSE->getNamedConcept()->getLexicalDeclContext(),
/*Final=*/false, CSE->getTemplateArguments(),
/*RelativeToPrimary=*/true,
+ /*Pattern=*/nullptr,
/*ForConstraintInstantiation=*/true);
return substituteParameterMappings(S, N, CSE->getNamedConcept(), MLTAL,
@@ -1800,8 +1805,8 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1,
return false;
}
- unsigned Depth1 = CalculateTemplateDepthForConstraints(*this, D1);
- unsigned Depth2 = CalculateTemplateDepthForConstraints(*this, D2);
+ unsigned Depth1 = CalculateTemplateDepthForConstraints(*this, D1, true);
+ unsigned Depth2 = CalculateTemplateDepthForConstraints(*this, D2, true);
for (size_t I = 0; I != AC1.size() && I != AC2.size(); ++I) {
if (Depth2 > Depth1) {
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 072f43d360ee1c..118873bc93ad4b 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -4510,10 +4510,10 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
adjustDeclContextForDeclaratorDecl(New, Old);
// Ensure the template parameters are compatible.
- if (NewTemplate && !TemplateParameterListsAreEqual(
- NewTemplate, NewTemplate->getTemplateParameters(),
- OldTemplate, OldTemplate->getTemplateParameters(),
- /*Complain=*/true, TPL_TemplateMatch))
+ if (NewTemplate &&
+ !TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
+ OldTemplate->getTemplateParameters(),
+ /*Complain=*/true, TPL_TemplateMatch))
return New->setInvalidDecl();
// C++ [class.mem]p1:
@@ -7663,7 +7663,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
: SourceLocation();
DeclResult Res = ActOnVarTemplateSpecialization(
S, D, TInfo, Previous, TemplateKWLoc, TemplateParams, SC,
- IsPartialSpecialization, IsMemberSpecialization);
+ IsPartialSpecialization);
if (Res.isInvalid())
return nullptr;
NewVD = cast<VarDecl>(Res.get());
@@ -7682,10 +7682,6 @@ NamedDecl *Sema::ActOnVariableDeclarator(
VarTemplateDecl::Create(Context, DC, D.getIdentifierLoc(), Name,
TemplateParams, NewVD);
NewVD->setDescribedVarTemplate(NewTemplate);
- // If we are providing an explicit specialization of a static variable
- // template, make a note of that.
- if (IsMemberSpecialization)
- NewTemplate->setMemberSpecialization();
}
// If this decl has an auto type in need of deduction, make a note of the
@@ -8063,6 +8059,12 @@ NamedDecl *Sema::ActOnVariableDeclarator(
? TPC_ClassTemplateMember
: TPC_VarTemplate))
NewVD->setInvalidDecl();
+
+ // If we are providing an explicit specialization of a static variable
+ // template, make a note of that.
+ if (PrevVarTemplate &&
+ PrevVarTemplate->getInstantiatedFromMemberTemplate())
+ PrevVarTemplate->setMemberSpecialization();
}
}
@@ -9869,8 +9871,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewFD);
FunctionTemplate->setLexicalDeclContext(CurContext);
NewFD->setDescribedFunctionTemplate(FunctionTemplate);
- if (isMemberSpecialization)
- FunctionTemplate->setMemberSpecialization();
// For source fidelity, store the other template param lists.
if (TemplateParamLists.size() > 1) {
@@ -12028,7 +12028,10 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// If this is an explicit specialization of a member that is a function
// template, mark it as a member specialization.
- if (IsMemberSpecialization) {
+ if (IsMemberSpecialization &&
+ NewTemplateDecl->getInstantiatedFromMemberTemplate()) {
+ NewTemplateDecl->setMemberSpecialization();
+ assert(OldTemplateDecl->isMemberSpecialization());
// Explicit specializations of a member template do not inherit deleted
// status from the parent member template that they are specializing.
if (OldFD->isDeleted()) {
@@ -17090,8 +17093,8 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
DeclResult Result = CheckClassTemplate(
S, TagSpec, TUK, KWLoc, SS, Name, NameLoc, Attrs, TemplateParams,
AS, ModulePrivateLoc,
- /*FriendLoc*/ SourceLocation(), TemplateParameterLists.drop_back(),
- isMemberSpecialization, SkipBody);
+ /*FriendLoc*/ SourceLocation(), TemplateParameterLists.size() - 1,
+ TemplateParameterLists.data(), SkipBody);
return Result.get();
} else {
// The "template<>" header is extraneous.
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 75d82c12e0c1f3..9cb2ed02a3f764 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -17416,8 +17416,8 @@ DeclResult Sema::ActOnTemplatedFriendTag(
return CheckClassTemplate(S, TagSpec, TagUseKind::Friend, TagLoc, SS,
Name, NameLoc, Attr, TemplateParams, AS_public,
/*ModulePrivateLoc=*/SourceLocation(),
- FriendLoc, TempParamLists.drop_back(),
- IsMemberSpecialization)
+ FriendLoc, TempParamLists.size() - 1,
+ TempParamLists.data())
.get();
} else {
// The "template<>" header is extraneous.
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index dfd56debc75e99..c7d48b81bc0347 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -1795,9 +1795,8 @@ DeclResult Sema::CheckClassTemplate(
CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc,
const ParsedAttributesView &Attr, TemplateParameterList *TemplateParams,
AccessSpecifier AS, SourceLocation ModulePrivateLoc,
- SourceLocation FriendLoc,
- ArrayRef<TemplateParameterList *> OuterTemplateParamLists,
- bool IsMemberSpecialization, SkipBodyInfo *SkipBody) {
+ SourceLocation FriendLoc, unsigned NumOuterTemplateParamLists,
+ TemplateParameterList **OuterTemplateParamLists, SkipBodyInfo *SkipBody) {
assert(TemplateParams && TemplateParams->size() > 0 &&
"No template parameters");
assert(TUK != TagUseKind::Reference &&
@@ -1985,6 +1984,19 @@ DeclResult Sema::CheckClassTemplate(
}
if (PrevClassTemplate) {
+ // Ensure that the template parameter lists are compatible. Skip this check
+ // for a friend in a dependent context: the template parameter list itself
+ // could be dependent.
+ if (!(TUK == TagUseKind::Friend && CurContext->isDependentContext()) &&
+ !TemplateParameterListsAreEqual(
+ TemplateCompareNewDeclInfo(SemanticContext ? SemanticContext
+ : CurContext,
+ CurContext, KWLoc),
+ TemplateParams, PrevClassTemplate,
+ PrevClassTemplate->getTemplateParameters(), /*Complain=*/true,
+ TPL_TemplateMatch))
+ return true;
+
// C++ [temp.class]p4:
// In a redeclaration, partial specialization, explicit
// specialization or explicit instantiation of a class template,
@@ -1999,6 +2011,30 @@ DeclResult Sema::CheckClassTemplate(
Diag(PrevRecordDecl->getLocation(), diag::note_previous_use);
Kind = PrevRecordDecl->getTagKind();
}
+
+ // Check for redefinition of this class template.
+ if (TUK == TagUseKind::Definition) {
+ if (TagDecl *Def = PrevRecordDecl->getDefinition()) {
+ // If we have a prior definition that is not visible, treat this as
+ // simply making that previous definition visible.
+ NamedDecl *Hidden = nullptr;
+ if (SkipBody && !hasVisibleDefinition(Def, &Hidden)) {
+ SkipBody->ShouldSkip = true;
+ SkipBody->Previous = Def;
+ auto *Tmpl = cast<CXXRecordDecl>(Hidden)->getDescribedClassTemplate();
+ assert(Tmpl && "original definition of a class template is not a "
+ "class template?");
+ makeMergedDefinitionVisible(Hidden);
+ makeMergedDefinitionVisible(Tmpl);
+ } else {
+ Diag(NameLoc, diag::err_redefinition) << Name;
+ Diag(Def->getLocation(), diag::note_previous_definition);
+ // FIXME: Would it make sense to try to "forget" the previous
+ // definition, as part of error recovery?
+ return true;
+ }
+ }
+ }
} else if (PrevDecl) {
// C++ [temp]p5:
// A class template shall not have the same name as any other
@@ -2010,6 +2046,23 @@ DeclResult Sema::CheckClassTemplate(
return true;
}
+ // Check the template parameter list of this declaration, possibly
+ // merging in the template parameter list from the previous class
+ // template declaration. Skip this check for a friend in a dependent
+ // context, because the template parameter list might be dependent.
+ if (!(TUK == TagUseKind::Friend && CurContext->isDependentContext()) &&
+ CheckTemplateParameterList(
+ TemplateParams,
+ PrevClassTemplate ? GetTemplateParameterList(PrevClassTemplate)
+ : nullptr,
+ (SS.isSet() && SemanticContext && SemanticContext->isRecord() &&
+ SemanticContext->isDependentContext())
+ ? TPC_ClassTemplateMember
+ : TUK == TagUseKind::Friend ? TPC_FriendClassTemplate
+ : TPC_ClassTemplate,
+ SkipBody))
+ Invalid = true;
+
if (SS.isSet()) {
// If the name of the template was qualified, we must be defining the
// template out-of-line.
@@ -2036,8 +2089,10 @@ DeclResult Sema::CheckClassTemplate(
PrevClassTemplate->getTemplatedDecl() : nullptr,
/*DelayTypeCreation=*/true);
SetNestedNameSpecifier(*this, NewClass, SS);
- if (!OuterTemplateParamLists.empty())
- NewClass->setTemplateParameterListsInfo(Context, OuterTemplateParamLists);
+ if (NumOuterTemplateParamLists > 0)
+ NewClass->setTemplateParameterListsInfo(
+ Context,
+ llvm::ArrayRef(OuterTemplateParamLists, NumOuterTemplateParamLists));
// Add alignment attributes if necessary; these attributes are checked when
// the ASTContext lays out the structure.
@@ -2050,10 +2105,7 @@ DeclResult Sema::CheckClassTemplate(
= ClassTemplateDecl::Create(Context, SemanticContext, NameLoc,
DeclarationName(Name), TemplateParams,
NewClass);
- // If we are providing an explicit specialization of a member that is a
- // class template, make a note of that.
- if (IsMemberSpecialization)
- NewTemplate->setMemberSpecialization();
+
if (ShouldAddRedecl)
NewTemplate->setPreviousDecl(PrevClassTemplate);
@@ -2068,6 +2120,12 @@ DeclResult Sema::CheckClassTemplate(
assert(T->isDependentType() && "Class template type is not dependent?");
(void)T;
+ // If we are providing an explicit specialization of a member that is a
+ // class template, make a note of that.
+ if (PrevClassTemplate &&
+ PrevClassTemplate->getInstantiatedFromMemberTemplate())
+ PrevClassTemplate->setMemberSpecialization();
+
// Set the access specifier.
if (!Invalid && TUK != TagUseKind::Friend &&
NewTemplate->getDeclContext()->isRecord())
@@ -2077,62 +2135,8 @@ DeclResult Sema::CheckClassTemplate(
NewClass->setLexicalDeclContext(CurContext);
NewTemplate->setLexicalDeclContext(CurContext);
- // Ensure that the template parameter lists are compatible. Skip this check
- // for a friend in a dependent context: the template parameter list itself
- // could be dependent.
- if (ShouldAddRedecl && PrevClassTemplate &&
- !TemplateParameterListsAreEqual(
- NewTemplate, TemplateParams, PrevClassTemplate,
- PrevClassTemplate->getTemplateParameters(),
- /*Complain=*/true, TPL_TemplateMatch))
- return true;
-
- // Check the template parameter list of this declaration, possibly
- // merging in the template parameter list from the previous class
- // template declaration. Skip this check for a friend in a dependent
- // context, because the template parameter list might be dependent.
- if (ShouldAddRedecl &&
- CheckTemplateParameterList(
- TemplateParams,
- PrevClassTemplate ? PrevClassTemplate->getTemplateParameters()
- : nullptr,
- (SS.isSet() && SemanticContext && SemanticContext->isRecord() &&
- SemanticContext->isDependentContext())
- ? TPC_ClassTemplateMember
- : TUK == TagUseKind::Friend ? TPC_FriendClassTemplate
- : TPC_ClassTemplate,
- SkipBody))
- Invalid = true;
-
- if (TUK == TagUseKind::Definition) {
- if (PrevClassTemplate) {
- // Check for redefinition of this class template.
- if (TagDecl *Def =
- PrevClassTemplate->getTemplatedDecl()->getDefinition()) {
- // If we have a prior definition that is not visible, treat this as
- // simply making that previous definition visible.
- NamedDecl *Hidden = nullptr;
- if (SkipBody && !hasVisibleDefinition(Def, &Hidden)) {
- SkipBody->ShouldSkip = true;
- SkipBody->Previous = Def;
- auto *Tmpl = cast<CXXRecordDecl>(Hidden)->getDescribedClassTemplate();
- assert(Tmpl && "original definition of a class template is not a "
- "class template?");
- makeMergedDefinitionVisible(Hidden);
- makeMergedDefinitionVisible(Tmpl);
- } else {
- Diag(NameLoc, diag::err_redefinition) << Name;
- Diag(Def->getLocation(), diag::note_previous_definition);
- // FIXME: Would it make sense to try to "forget" the previous
- // definition, as part of error recovery?
- return true;
- }
- }
- }
-
- if (!SkipBody || !SkipBody->ShouldSkip)
- NewClass->startDefinition();
- }
+ if (TUK == TagUseKind::Definition && (!SkipBody || !SkipBody->ShouldSkip))
+ NewClass->startDefinition();
ProcessDeclAttributeList(S, NewClass, Attr);
ProcessAPINotes(NewClass);
@@ -4129,8 +4133,7 @@ void Sema::CheckDeductionGuideTemplate(FunctionTemplateDecl *TD) {
DeclResult Sema::ActOnVarTemplateSpecialization(
Scope *S, Declarator &D, TypeSourceInfo *DI, LookupResult &Previous,
SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams,
- StorageClass SC, bool IsPartialSpecialization,
- bool IsMemberSpecialization) {
+ StorageClass SC, bool IsPartialSpecialization) {
// D must be variable template id.
assert(D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId &&
"Variable template specialization is declared with a template id.");
@@ -4248,16 +4251,17 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
Context, VarTemplate->getDeclContext(), TemplateKWLoc,
TemplateNameLoc, TemplateParams, VarTemplate, DI->getType(), DI, SC,
CanonicalConverted);
- // If we are providing an explicit specialization of a member variable
- // template specialization, make a note of that.
- if (IsMemberSpecialization)
- Partial->setMemberSpecialization();
Partial->setTemplateArgsAsWritten(TemplateArgs);
if (!PrevPartial)
VarTemplate->AddPartialSpecialization(Partial, InsertPos);
Specialization = Partial;
+ // If we are providing an explicit specialization of a member variable
+ // template specialization, make a note of that.
+ if (PrevPartial && PrevPartial->getInstantiatedFromMember())
+ PrevPartial->setMemberSpecialization();
+
CheckTemplatePartialSpecialization(Partial);
} else {
// Create a new class template specialization declaration node for
@@ -5772,7 +5776,9 @@ bool Sema::CheckTemplateArgumentList(
MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(
Template, NewContext, /*Final=*/false, CanonicalConverted,
- /*RelativeToPrimary=*/true, /*ForConceptInstantiation=*/true);
+ /*RelativeToPrimary=*/true,
+ /*Pattern=*/nullptr,
+ /*ForConceptInstantiation=*/true);
if (EnsureTemplateArgumentListConstraints(
Template, MLTAL,
SourceRange(TemplateLoc, TemplateArgs.getRAngleLoc()))) {
@@ -8461,12 +8467,15 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
Diag(TemplateNameLoc, diag::err_partial_spec_args_match_primary_template)
<< /*class template*/ 0 << (TUK == TagUseKind::Definition)
<< FixItHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc));
- return CheckClassTemplate(
- S, TagSpec, TUK, KWLoc, SS, ClassTemplate->getIdentifier(),
- TemplateNameLoc, Attr, TemplateParams, AS_none,
- /*ModulePrivateLoc=*/SourceLocation(),
- /*FriendLoc*/ SourceLocation(), TemplateParameterLists.drop_back(),
- isMemberSpecialization);
+ return CheckClassTemplate(S, TagSpec, TUK, KWLoc, SS,
+ ClassTemplate->getIdentifier(),
+ TemplateNameLoc,
+ Attr,
+ TemplateParams,
+ AS_none, /*ModulePrivateLoc=*/SourceLocation(),
+ /*FriendLoc*/SourceLocation(),
+ TemplateParameterLists.size() - 1,
+ TemplateParameterLists.data());
}
// Create a new class template partial specialization declaration node.
@@ -8476,11 +8485,6 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
ClassTemplatePartialSpecializationDecl::Create(
Context, Kind, DC, KWLoc, TemplateNameLoc, TemplateParams,
ClassTemplate, CanonicalConverted, CanonType, PrevPartial);
-
- // If we are providing an explicit specialization of a member class
- // template specialization, make a note of that.
- if (isMemberSpecialization)
- Partial->setMemberSpecialization();
Partial->setTemplateArgsAsWritten(TemplateArgs);
SetNestedNameSpecifier(*this, Partial, SS);
if (TemplateParameterLists.size() > 1 && SS.isSet()) {
@@ -8492,6 +8496,11 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
ClassTemplate->AddPartialSpecialization(Partial, InsertPos);
Specialization = Partial;
+ // If we are providing an explicit specialization of a member class
+ // template specialization, make a note of that.
+ if (PrevPartial && PrevPartial->getInstantiatedFromMember())
+ PrevPartial->setMemberSpecialization();
+
CheckTemplatePartialSpecialization(Partial);
} else {
// Create a new class template specialization declaration node for
@@ -11290,8 +11299,8 @@ class ExplicitSpecializationVisibilityChecker {
template<typename TemplDecl>
void checkTemplate(TemplDecl *TD) {
- if (TD->getMostRecentDecl()->isMemberSpecialization()) {
- if (!CheckMemberSpecialization(TD->getMostRecentDecl()))
+ if (TD->isMemberSpecialization()) {
+ if (!CheckMemberSpecialization(TD))
diagnose(TD->getMostRecentDecl(), false);
}
}
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index aa62cfa7dcbd17..d106874c4c5bda 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3138,6 +3138,20 @@ template<>
struct IsPartialSpecialization<VarTemplatePartialSpecializationDecl> {
static constexpr bool value = true;
};
+template <typename TemplateDeclT>
+static bool DeducedArgsNeedReplacement(TemplateDeclT *Template) {
+ return false;
+}
+template <>
+bool DeducedArgsNeedReplacement<VarTemplatePartialSpecializationDecl>(
+ VarTemplatePartialSpecializationDecl *Spec) {
+ return !Spec->isClassScopeExplicitSpecialization();
+}
+template <>
+bool DeducedArgsNeedReplacement<ClassTemplatePartialSpecializationDecl>(
+ ClassTemplatePartialSpecializationDecl *Spec) {
+ return !Spec->isClassScopeExplicitSpecialization();
+}
template <typename TemplateDeclT>
static TemplateDeductionResult
@@ -3148,10 +3162,23 @@ CheckDeducedArgumentConstraints(Sema &S, TemplateDeclT *Template,
llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
Template->getAssociatedConstraints(AssociatedConstraints);
+ std::optional<ArrayRef<TemplateArgument>> Innermost;
+ // If we don't need to replace the deduced template arguments,
+ // we can add them immediately as the inner-most argument list.
+ if (!DeducedArgsNeedReplacement(Template))
+ Innermost = CanonicalDeducedArgs;
+
MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
- Template, Template->getDeclContext(), /*Final=*/false,
- /*Innermost=*/CanonicalDeducedArgs, /*RelativeToPrimary=*/true,
- /*ForConstraintInstantiation=*/true);
+ Template, Template->getDeclContext(), /*Final=*/false, Innermost,
+ /*RelativeToPrimary=*/true, /*Pattern=*/
+ nullptr, /*ForConstraintInstantiation=*/true);
+
+ // getTemplateInstantiationArgs picks up the non-deduced version of the
+ // template args when this is a variable template partial specialization and
+ // not class-scope explicit specialization, so replace with Deduced Args
+ // instead of adding to inner-most.
+ if (!Innermost)
+ MLTAL.replaceInnermostTemplateArguments(Template, CanonicalDeducedArgs);
if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL,
Info.getLocation(),
diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index ca93c840f03215..545da21183c3c4 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -765,7 +765,7 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
}
// Template arguments used to transform the template arguments in
// DeducedResults.
- SmallVector<TemplateArgument> InnerArgsForBuildingRC(
+ SmallVector<TemplateArgument> TemplateArgsForBuildingRC(
F->getTemplateParameters()->size());
// Transform the transformed template args
MultiLevelTemplateArgumentList Args;
@@ -778,30 +778,33 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
NamedDecl *TP = F->getTemplateParameters()->getParam(Index);
MultiLevelTemplateArgumentList Args;
Args.setKind(TemplateSubstitutionKind::Rewrite);
- Args.addOuterTemplateArguments(InnerArgsForBuildingRC);
+ Args.addOuterTemplateArguments(TemplateArgsForBuildingRC);
// Rebuild the template parameter with updated depth and index.
NamedDecl *NewParam =
transformTemplateParameter(SemaRef, F->getDeclContext(), TP, Args,
/*NewIndex=*/FirstUndeducedParamIdx,
getDepthAndIndex(TP).first + AdjustDepth);
FirstUndeducedParamIdx += 1;
- assert(InnerArgsForBuildingRC[Index].isNull());
- InnerArgsForBuildingRC[Index] = Context.getInjectedTemplateArg(NewParam);
+ assert(TemplateArgsForBuildingRC[Index].isNull());
+ TemplateArgsForBuildingRC[Index] =
+ Context.getInjectedTemplateArg(NewParam);
continue;
}
TemplateArgumentLoc Input =
SemaRef.getTrivialTemplateArgumentLoc(D, QualType(), SourceLocation{});
TemplateArgumentLoc Output;
if (!SemaRef.SubstTemplateArgument(Input, Args, Output)) {
- assert(InnerArgsForBuildingRC[Index].isNull() &&
+ assert(TemplateArgsForBuildingRC[Index].isNull() &&
"InstantiatedArgs must be null before setting");
- InnerArgsForBuildingRC[Index] = Output.getArgument();
+ TemplateArgsForBuildingRC[Index] = Output.getArgument();
}
}
- // A list of template arguments for transforming the require-clause using
- // the transformed template arguments as the template argument list of F.
- //
+ // A list of template arguments for transforming the require-clause of F.
+ // It must contain the entire set of template argument lists.
+ MultiLevelTemplateArgumentList ArgsForBuildingRC;
+ ArgsForBuildingRC.setKind(clang::TemplateSubstitutionKind::Rewrite);
+ ArgsForBuildingRC.addOuterTemplateArguments(TemplateArgsForBuildingRC);
// For 2), if the underlying deduction guide F is nested in a class template,
// we need the entire template argument list, as the constraint AST in the
// require-clause of F remains completely uninstantiated.
@@ -824,15 +827,25 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
// - The occurrence of U in the function parameter is [depth:0, index:0]
// - The template parameter of U is [depth:0, index:0]
//
+ // We add the outer template arguments which is [int] to the multi-level arg
+ // list to ensure that the occurrence U in `C<U>` will be replaced with int
+ // during the substitution.
+ //
// NOTE: The underlying deduction guide F is instantiated -- either from an
// explicitly-written deduction guide member, or from a constructor.
- MultiLevelTemplateArgumentList ArgsForBuildingRC =
- SemaRef.getTemplateInstantiationArgs(F, F->getLexicalDeclContext(),
- /*Final=*/false,
- /*Innermost=*/InnerArgsForBuildingRC,
- /*RelativeToPrimary=*/true,
- /*ForConstraintInstantiation=*/true);
- ArgsForBuildingRC.setKind(clang::TemplateSubstitutionKind::Rewrite);
+ // getInstantiatedFromMemberTemplate() can only handle the former case, so we
+ // check the DeclContext kind.
+ if (F->getLexicalDeclContext()->getDeclKind() ==
+ clang::Decl::ClassTemplateSpecialization) {
+ auto OuterLevelArgs = SemaRef.getTemplateInstantiationArgs(
+ F, F->getLexicalDeclContext(),
+ /*Final=*/false, /*Innermost=*/std::nullopt,
+ /*RelativeToPrimary=*/true,
+ /*Pattern=*/nullptr,
+ /*ForConstraintInstantiation=*/true);
+ for (auto It : OuterLevelArgs)
+ ArgsForBuildingRC.addOuterTemplateArguments(It.Args);
+ }
ExprResult E = SemaRef.SubstExpr(RC, ArgsForBuildingRC);
if (E.isInvalid())
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 5b5e50f668b25d..7d42cf6b8cced3 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -52,6 +52,38 @@ using namespace sema;
//===----------------------------------------------------------------------===/
namespace {
+namespace TemplateInstArgsHelpers {
+struct Response {
+ const Decl *NextDecl = nullptr;
+ bool IsDone = false;
+ bool ClearRelativeToPrimary = true;
+ static Response Done() {
+ Response R;
+ R.IsDone = true;
+ return R;
+ }
+ static Response ChangeDecl(const Decl *ND) {
+ Response R;
+ R.NextDecl = ND;
+ return R;
+ }
+ static Response ChangeDecl(const DeclContext *Ctx) {
+ Response R;
+ R.NextDecl = Decl::castFromDeclContext(Ctx);
+ return R;
+ }
+
+ static Response UseNextDecl(const Decl *CurDecl) {
+ return ChangeDecl(CurDecl->getDeclContext());
+ }
+
+ static Response DontClearRelativeToPrimaryNextDecl(const Decl *CurDecl) {
+ Response R = Response::UseNextDecl(CurDecl);
+ R.ClearRelativeToPrimary = false;
+ return R;
+ }
+};
+
// Retrieve the primary template for a lambda call operator. It's
// unfortunate that we only have the mappings of call operators rather
// than lambda classes.
@@ -139,396 +171,374 @@ bool isLambdaEnclosedByTypeAliasDecl(
.TraverseType(Underlying);
}
-struct TemplateInstantiationArgumentCollecter
- : DeclVisitor<TemplateInstantiationArgumentCollecter, Decl *> {
- Sema &S;
- MultiLevelTemplateArgumentList &Result;
- std::optional<ArrayRef<TemplateArgument>> Innermost;
- bool RelativeToPrimary;
- bool ForConstraintInstantiation;
-
- TemplateInstantiationArgumentCollecter(
- Sema &S, MultiLevelTemplateArgumentList &Result,
- std::optional<ArrayRef<TemplateArgument>> Innermost,
- bool RelativeToPrimary, bool ForConstraintInstantiation)
- : S(S), Result(Result), Innermost(Innermost),
- RelativeToPrimary(RelativeToPrimary),
- ForConstraintInstantiation(ForConstraintInstantiation) {}
-
- Decl *Done() { return nullptr; }
-
- Decl *ChangeDecl(const Decl *D) {
- RelativeToPrimary = false;
- return const_cast<Decl *>(D);
- }
-
- Decl *ChangeDecl(const DeclContext *DC) {
- return ChangeDecl(Decl::castFromDeclContext(DC));
- }
-
- Decl *UseNextDecl(const Decl *D) { return ChangeDecl(D->getDeclContext()); }
-
- void AddInnermostTemplateArguments(const Decl *D) {
- assert(Innermost);
- Result.addOuterTemplateArguments(const_cast<Decl *>(D), *Innermost,
- /*Final=*/false);
- Innermost.reset();
- }
-
- void AddOuterTemplateArguments(const Decl *D, ArrayRef<TemplateArgument> Args,
- bool Final) {
- Result.addOuterTemplateArguments(const_cast<Decl *>(D), Args, Final);
+// Add template arguments from a variable template instantiation.
+Response
+HandleVarTemplateSpec(const VarTemplateSpecializationDecl *VarTemplSpec,
+ MultiLevelTemplateArgumentList &Result,
+ bool SkipForSpecialization) {
+ // For a class-scope explicit specialization, there are no template arguments
+ // at this level, but there may be enclosing template arguments.
+ if (VarTemplSpec->isClassScopeExplicitSpecialization())
+ return Response::DontClearRelativeToPrimaryNextDecl(VarTemplSpec);
+
+ // We're done when we hit an explicit specialization.
+ if (VarTemplSpec->getSpecializationKind() == TSK_ExplicitSpecialization &&
+ !isa<VarTemplatePartialSpecializationDecl>(VarTemplSpec))
+ return Response::Done();
+
+ // If this variable template specialization was instantiated from a
+ // specialized member that is a variable template, we're done.
+ assert(VarTemplSpec->getSpecializedTemplate() && "No variable template?");
+ llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
+ Specialized = VarTemplSpec->getSpecializedTemplateOrPartial();
+ if (VarTemplatePartialSpecializationDecl *Partial =
+ Specialized.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
+ if (!SkipForSpecialization)
+ Result.addOuterTemplateArguments(
+ Partial, VarTemplSpec->getTemplateInstantiationArgs().asArray(),
+ /*Final=*/false);
+ if (Partial->isMemberSpecialization())
+ return Response::Done();
+ } else {
+ VarTemplateDecl *Tmpl = Specialized.get<VarTemplateDecl *>();
+ if (!SkipForSpecialization)
+ Result.addOuterTemplateArguments(
+ Tmpl, VarTemplSpec->getTemplateInstantiationArgs().asArray(),
+ /*Final=*/false);
+ if (Tmpl->isMemberSpecialization())
+ return Response::Done();
}
+ return Response::DontClearRelativeToPrimaryNextDecl(VarTemplSpec);
+}
- Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTPD) {
- if (Innermost)
- AddInnermostTemplateArguments(TTPD);
- else if (ForConstraintInstantiation)
- AddOuterTemplateArguments(nullptr, std::nullopt, /*Final=*/false);
-
- for (unsigned Depth = TTPD->getDepth() + 1; Depth--;)
- AddOuterTemplateArguments(nullptr, std::nullopt, /*Final=*/false);
-
- return Done();
- }
+// If we have a template template parameter with translation unit context,
+// then we're performing substitution into a default template argument of
+// this template template parameter before we've constructed the template
+// that will own this template template parameter. In this case, we
+// use empty template parameter lists for all of the outer templates
+// to avoid performing any substitutions.
+Response
+HandleDefaultTempArgIntoTempTempParam(const TemplateTemplateParmDecl *TTP,
+ MultiLevelTemplateArgumentList &Result) {
+ for (unsigned I = 0, N = TTP->getDepth() + 1; I != N; ++I)
+ Result.addOuterTemplateArguments(std::nullopt);
+ return Response::Done();
+}
- Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *FTD) {
- assert(
- (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
- "outer template not instantiated?");
+Response HandlePartialClassTemplateSpec(
+ const ClassTemplatePartialSpecializationDecl *PartialClassTemplSpec,
+ MultiLevelTemplateArgumentList &Result, bool SkipForSpecialization) {
+ if (!SkipForSpecialization)
+ Result.addOuterRetainedLevels(PartialClassTemplSpec->getTemplateDepth());
+ return Response::Done();
+}
- if (Innermost)
- AddInnermostTemplateArguments(FTD);
- else if (ForConstraintInstantiation)
- AddOuterTemplateArguments(FTD, FTD->getInjectedTemplateArgs(),
- /*Final=*/false);
+// Add template arguments from a class template instantiation.
+Response
+HandleClassTemplateSpec(const ClassTemplateSpecializationDecl *ClassTemplSpec,
+ MultiLevelTemplateArgumentList &Result,
+ bool SkipForSpecialization) {
+ if (!ClassTemplSpec->isClassScopeExplicitSpecialization()) {
+ // We're done when we hit an explicit specialization.
+ if (ClassTemplSpec->getSpecializationKind() == TSK_ExplicitSpecialization &&
+ !isa<ClassTemplatePartialSpecializationDecl>(ClassTemplSpec))
+ return Response::Done();
- if (FTD->isMemberSpecialization())
- return Done();
+ if (!SkipForSpecialization)
+ Result.addOuterTemplateArguments(
+ const_cast<ClassTemplateSpecializationDecl *>(ClassTemplSpec),
+ ClassTemplSpec->getTemplateInstantiationArgs().asArray(),
+ /*Final=*/false);
- if (FTD->getFriendObjectKind())
- return ChangeDecl(FTD->getLexicalDeclContext());
- return UseNextDecl(FTD);
+ // If this class template specialization was instantiated from a
+ // specialized member that is a class template, we're done.
+ assert(ClassTemplSpec->getSpecializedTemplate() && "No class template?");
+ if (ClassTemplSpec->getSpecializedTemplate()->isMemberSpecialization())
+ return Response::Done();
+
+ // If this was instantiated from a partial template specialization, we need
+ // to get the next level of declaration context from the partial
+ // specialization, as the ClassTemplateSpecializationDecl's
+ // DeclContext/LexicalDeclContext will be for the primary template.
+ if (auto *InstFromPartialTempl = ClassTemplSpec->getSpecializedTemplateOrPartial()
+ .dyn_cast<ClassTemplatePartialSpecializationDecl *>())
+ return Response::ChangeDecl(InstFromPartialTempl->getLexicalDeclContext());
}
+ return Response::UseNextDecl(ClassTemplSpec);
+}
- Decl *VisitVarTemplateDecl(VarTemplateDecl *VTD) {
- assert(
- (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
- "outer template not instantiated?");
-
- if (Innermost)
- AddInnermostTemplateArguments(VTD);
- else if (ForConstraintInstantiation)
- AddOuterTemplateArguments(VTD, VTD->getInjectedTemplateArgs(),
- /*Final=*/false);
-
- if (VTD->isMemberSpecialization())
- return Done();
-
- return UseNextDecl(VTD);
- }
+Response HandleFunction(Sema &SemaRef, const FunctionDecl *Function,
+ MultiLevelTemplateArgumentList &Result,
+ const FunctionDecl *Pattern, bool RelativeToPrimary,
+ bool ForConstraintInstantiation,
+ bool ForDefaultArgumentSubstitution) {
+ // Add template arguments from a function template specialization.
+ if (!RelativeToPrimary &&
+ Function->getTemplateSpecializationKindForInstantiation() ==
+ TSK_ExplicitSpecialization)
+ return Response::Done();
+
+ if (!RelativeToPrimary &&
+ Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) {
+ // This is an implicit instantiation of an explicit specialization. We
+ // don't get any template arguments from this function but might get
+ // some from an enclosing template.
+ return Response::UseNextDecl(Function);
+ } else if (const TemplateArgumentList *TemplateArgs =
+ Function->getTemplateSpecializationArgs()) {
+ // Add the template arguments for this specialization.
+ Result.addOuterTemplateArguments(const_cast<FunctionDecl *>(Function),
+ TemplateArgs->asArray(),
+ /*Final=*/false);
- Decl *VisitVarTemplatePartialSpecializationDecl(
- VarTemplatePartialSpecializationDecl *VTPSD) {
+ if (RelativeToPrimary &&
+ (Function->getTemplateSpecializationKind() ==
+ TSK_ExplicitSpecialization ||
+ (Function->getFriendObjectKind() &&
+ !Function->getPrimaryTemplate()->getFriendObjectKind())))
+ return Response::UseNextDecl(Function);
+
+ // If this function was instantiated from a specialized member that is
+ // a function template, we're done.
+ assert(Function->getPrimaryTemplate() && "No function template?");
+ if (!ForDefaultArgumentSubstitution &&
+ Function->getPrimaryTemplate()->isMemberSpecialization())
+ return Response::Done();
+
+ // If this function is a generic lambda specialization, we are done.
+ if (!ForConstraintInstantiation &&
+ isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function))
+ return Response::Done();
+
+ } else if (Function->getDescribedFunctionTemplate()) {
assert(
(ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
- "outer template not instantiated?");
-
- if (Innermost)
- AddInnermostTemplateArguments(VTPSD);
- else if (ForConstraintInstantiation)
- AddOuterTemplateArguments(VTPSD, VTPSD->getTemplateArgs().asArray(),
- /*Final=*/false);
-
- if (VTPSD->isMemberSpecialization())
- return Done();
-
- return UseNextDecl(VTPSD);
+ "Outer template not instantiated?");
}
-
- Decl *VisitClassTemplateDecl(ClassTemplateDecl *CTD) {
- assert(
- (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
- "outer template not instantiated?");
-
- if (Innermost)
- AddInnermostTemplateArguments(CTD);
- else if (ForConstraintInstantiation)
- AddOuterTemplateArguments(CTD, CTD->getInjectedTemplateArgs(),
- /*Final=*/false);
-
- if (CTD->isMemberSpecialization())
- return Done();
-
- if (CTD->getFriendObjectKind())
- return ChangeDecl(CTD->getLexicalDeclContext());
- return UseNextDecl(CTD);
+ // If this is a friend or local declaration and it declares an entity at
+ // namespace scope, take arguments from its lexical parent
+ // instead of its semantic parent, unless of course the pattern we're
+ // instantiating actually comes from the file's context!
+ if ((Function->getFriendObjectKind() || Function->isLocalExternDecl()) &&
+ Function->getNonTransparentDeclContext()->isFileContext() &&
+ (!Pattern || !Pattern->getLexicalDeclContext()->isFileContext())) {
+ return Response::ChangeDecl(Function->getLexicalDeclContext());
}
- Decl *VisitClassTemplatePartialSpecializationDecl(
- ClassTemplatePartialSpecializationDecl *CTPSD) {
- assert(
- (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
- "outer template not instantiated?");
-
- if (Innermost)
- AddInnermostTemplateArguments(CTPSD);
- else if (ForConstraintInstantiation)
- AddOuterTemplateArguments(CTPSD, CTPSD->getTemplateArgs().asArray(),
- /*Final=*/false);
+ if (ForConstraintInstantiation && Function->getFriendObjectKind())
+ return Response::ChangeDecl(Function->getLexicalDeclContext());
+ return Response::UseNextDecl(Function);
+}
- if (CTPSD->isMemberSpecialization())
- return Done();
+Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD,
+ MultiLevelTemplateArgumentList &Result) {
+ if (!isa<ClassTemplateSpecializationDecl>(FTD->getDeclContext())) {
+ Result.addOuterTemplateArguments(
+ const_cast<FunctionTemplateDecl *>(FTD),
+ const_cast<FunctionTemplateDecl *>(FTD)->getInjectedTemplateArgs(),
+ /*Final=*/false);
+
+ NestedNameSpecifier *NNS = FTD->getTemplatedDecl()->getQualifier();
+
+ while (const Type *Ty = NNS ? NNS->getAsType() : nullptr) {
+ if (NNS->isInstantiationDependent()) {
+ if (const auto *TSTy = Ty->getAs<TemplateSpecializationType>()) {
+ ArrayRef<TemplateArgument> Arguments = TSTy->template_arguments();
+ // Prefer template arguments from the injected-class-type if possible.
+ // For example,
+ // ```cpp
+ // template <class... Pack> struct S {
+ // template <class T> void foo();
+ // };
+ // template <class... Pack> template <class T>
+ // ^^^^^^^^^^^^^ InjectedTemplateArgs
+ // They're of kind TemplateArgument::Pack, not of
+ // TemplateArgument::Type.
+ // void S<Pack...>::foo() {}
+ // ^^^^^^^
+ // TSTy->template_arguments() (which are of PackExpansionType)
+ // ```
+ // This meets the contract in
+ // TreeTransform::TryExpandParameterPacks that the template arguments
+ // for unexpanded parameters should be of a Pack kind.
+ if (TSTy->isCurrentInstantiation()) {
+ auto *RD = TSTy->getCanonicalTypeInternal()->getAsCXXRecordDecl();
+ if (ClassTemplateDecl *CTD = RD->getDescribedClassTemplate())
+ Arguments = CTD->getInjectedTemplateArgs();
+ else if (auto *Specialization =
+ dyn_cast<ClassTemplateSpecializationDecl>(RD))
+ Arguments =
+ Specialization->getTemplateInstantiationArgs().asArray();
+ }
+ Result.addOuterTemplateArguments(
+ TSTy->getTemplateName().getAsTemplateDecl(), Arguments,
+ /*Final=*/false);
+ }
+ }
- return UseNextDecl(CTPSD);
+ NNS = NNS->getPrefix();
+ }
}
- Decl *VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *TATD) {
- assert(
- (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
- "outer template not instantiated?");
- if (Innermost)
- AddInnermostTemplateArguments(TATD);
- else if (ForConstraintInstantiation)
- AddOuterTemplateArguments(TATD, TATD->getInjectedTemplateArgs(),
- /*Final=*/false);
-
- return UseNextDecl(TATD);
- }
+ return Response::ChangeDecl(FTD->getLexicalDeclContext());
+}
- Decl *VisitConceptDecl(ConceptDecl *CD) {
+Response HandleRecordDecl(Sema &SemaRef, const CXXRecordDecl *Rec,
+ MultiLevelTemplateArgumentList &Result,
+ ASTContext &Context,
+ bool ForConstraintInstantiation) {
+ if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) {
assert(
(ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
- "outer template not instantiated?");
- if (Innermost)
- AddInnermostTemplateArguments(CD);
-
- return UseNextDecl(CD);
+ "Outer template not instantiated?");
+ if (ClassTemplate->isMemberSpecialization())
+ return Response::Done();
+ if (ForConstraintInstantiation)
+ Result.addOuterTemplateArguments(const_cast<CXXRecordDecl *>(Rec),
+ ClassTemplate->getInjectedTemplateArgs(),
+ /*Final=*/false);
}
- Decl *VisitFunctionDecl(FunctionDecl *FD) {
- assert(!FD->getDescribedFunctionTemplate() &&
- "not for templated declarations");
-
- if (!RelativeToPrimary) {
- // Add template arguments from a function template specialization.
- if (const MemberSpecializationInfo *MSI =
- FD->getMemberSpecializationInfo();
- MSI &&
- MSI->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
- return Done();
-
- // This is an implicit instantiation of an explicit specialization. We
- // don't get any template arguments from this function but might get
- // some from an enclosing template.
- if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
- return UseNextDecl(FD);
- }
-
- if (const TemplateArgumentList *TemplateArgs =
- FD->getTemplateSpecializationArgs()) {
- // Add the template arguments for this specialization.
- if (Innermost)
- AddInnermostTemplateArguments(FD);
- else
- AddOuterTemplateArguments(FD, TemplateArgs->asArray(), /*Final=*/false);
-
- if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization ||
- (FD->getFriendObjectKind() &&
- !FD->getPrimaryTemplate()->getFriendObjectKind()))
- return UseNextDecl(FD);
-
- // If this function was instantiated from a specialized member that is
- // a function template, we're done.
- assert(FD->getPrimaryTemplate() && "No function template?");
- if (FD->getPrimaryTemplate()->isMemberSpecialization())
- return Done();
-
- // If this function is a generic lambda specialization, we are done.
- if (!ForConstraintInstantiation &&
- isGenericLambdaCallOperatorOrStaticInvokerSpecialization(FD))
- return Done();
- }
-
- // If this is a friend or local declaration and it declares an entity at
- // namespace scope, take arguments from its lexical parent
- // instead of its semantic parent, unless of course the pattern we're
- // instantiating actually comes from the file's context!
- if ((FD->getFriendObjectKind() || FD->isLocalExternDecl()) &&
- FD->getNonTransparentDeclContext()->isFileContext()) {
- return ChangeDecl(FD->getLexicalDeclContext());
- }
-
- if (ForConstraintInstantiation && FD->getFriendObjectKind())
- return ChangeDecl(FD->getLexicalDeclContext());
- return UseNextDecl(FD);
+ if (const MemberSpecializationInfo *MSInfo =
+ Rec->getMemberSpecializationInfo())
+ if (MSInfo->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+ return Response::Done();
+
+ bool IsFriend = Rec->getFriendObjectKind() ||
+ (Rec->getDescribedClassTemplate() &&
+ Rec->getDescribedClassTemplate()->getFriendObjectKind());
+ if (ForConstraintInstantiation && IsFriend &&
+ Rec->getNonTransparentDeclContext()->isFileContext()) {
+ return Response::ChangeDecl(Rec->getLexicalDeclContext());
}
- Decl *VisitCXXRecordDecl(CXXRecordDecl *RD) {
- assert(!RD->getDescribedClassTemplate() &&
- "not for templated declarations");
-
- if (const MemberSpecializationInfo *MSI = RD->getMemberSpecializationInfo();
- MSI &&
- MSI->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
- return Done();
-
- if (ForConstraintInstantiation && RD->getFriendObjectKind() &&
- RD->getNonTransparentDeclContext()->isFileContext()) {
- return ChangeDecl(RD->getLexicalDeclContext());
- }
-
- // This is to make sure we pick up the VarTemplateSpecializationDecl or the
- // TypeAliasTemplateDecl that this lambda is defined inside of.
- if (RD->isLambda()) {
- if (Decl *LCD = RD->getLambdaContextDecl())
- return ChangeDecl(LCD);
- // Retrieve the template arguments for a using alias declaration.
- // This is necessary for constraint checking, since we always keep
- // constraints relative to the primary template.
- if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl(S);
- ForConstraintInstantiation && TypeAlias) {
- if (isLambdaEnclosedByTypeAliasDecl(RD->getLambdaCallOperator(),
- TypeAlias.PrimaryTypeAliasDecl)) {
- AddOuterTemplateArguments(TypeAlias.Template,
- TypeAlias.AssociatedTemplateArguments,
- /*Final=*/false);
- // Visit the parent of the current type alias declaration rather than
- // the lambda thereof.
- // E.g., in the following example:
- // struct S {
- // template <class> using T = decltype([]<Concept> {} ());
- // };
- // void foo() {
- // S::T var;
- // }
- // The instantiated lambda expression (which we're visiting at 'var')
- // has a function DeclContext 'foo' rather than the Record DeclContext
- // S. This seems to be an oversight to me that we may want to set a
- // Sema Context from the CXXScopeSpec before substituting into T.
- return ChangeDecl(TypeAlias.Template->getDeclContext());
- }
+ // This is to make sure we pick up the VarTemplateSpecializationDecl or the
+ // TypeAliasTemplateDecl that this lambda is defined inside of.
+ if (Rec->isLambda()) {
+ if (const Decl *LCD = Rec->getLambdaContextDecl())
+ return Response::ChangeDecl(LCD);
+ // Retrieve the template arguments for a using alias declaration.
+ // This is necessary for constraint checking, since we always keep
+ // constraints relative to the primary template.
+ if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl(SemaRef);
+ ForConstraintInstantiation && TypeAlias) {
+ if (isLambdaEnclosedByTypeAliasDecl(Rec->getLambdaCallOperator(),
+ TypeAlias.PrimaryTypeAliasDecl)) {
+ Result.addOuterTemplateArguments(TypeAlias.Template,
+ TypeAlias.AssociatedTemplateArguments,
+ /*Final=*/false);
+ // Visit the parent of the current type alias declaration rather than
+ // the lambda thereof.
+ // E.g., in the following example:
+ // struct S {
+ // template <class> using T = decltype([]<Concept> {} ());
+ // };
+ // void foo() {
+ // S::T var;
+ // }
+ // The instantiated lambda expression (which we're visiting at 'var')
+ // has a function DeclContext 'foo' rather than the Record DeclContext
+ // S. This seems to be an oversight to me that we may want to set a
+ // Sema Context from the CXXScopeSpec before substituting into T.
+ return Response::ChangeDecl(TypeAlias.Template->getDeclContext());
}
}
-
- return UseNextDecl(RD);
- }
-
- Decl *
- VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *CTSD) {
- // For a class-scope explicit specialization, there are no template
- // arguments at this level, but there may be enclosing template arguments.
- if (CTSD->isClassScopeExplicitSpecialization())
- return UseNextDecl(CTSD);
-
- // We're done when we hit an explicit specialization.
- if (CTSD->getSpecializationKind() == TSK_ExplicitSpecialization)
- return Done();
-
- if (Innermost)
- AddInnermostTemplateArguments(CTSD);
- else
- AddOuterTemplateArguments(CTSD,
- CTSD->getTemplateInstantiationArgs().asArray(),
- /*Final=*/false);
-
- // If this class template specialization was instantiated from a
- // specialized member that is a class template, we're done.
- assert(CTSD->getSpecializedTemplate() && "No class template?");
- llvm::PointerUnion<ClassTemplateDecl *,
- ClassTemplatePartialSpecializationDecl *>
- Specialized = CTSD->getSpecializedTemplateOrPartial();
- if (auto *CTPSD =
- Specialized.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
- if (CTPSD->isMemberSpecialization())
- return Done();
- } else {
- auto *CTD = Specialized.get<ClassTemplateDecl *>();
- if (CTD->isMemberSpecialization())
- return Done();
- }
- return UseNextDecl(CTSD);
- }
-
- Decl *
- VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *VTSD) {
- // For a class-scope explicit specialization, there are no template
- // arguments at this level, but there may be enclosing template arguments.
- if (VTSD->isClassScopeExplicitSpecialization())
- return UseNextDecl(VTSD);
-
- // We're done when we hit an explicit specialization.
- if (VTSD->getSpecializationKind() == TSK_ExplicitSpecialization)
- return Done();
-
- if (Innermost)
- AddInnermostTemplateArguments(VTSD);
- else
- AddOuterTemplateArguments(VTSD,
- VTSD->getTemplateInstantiationArgs().asArray(),
- /*Final=*/false);
-
- // If this variable template specialization was instantiated from a
- // specialized member that is a variable template, we're done.
- assert(VTSD->getSpecializedTemplate() && "No variable template?");
- llvm::PointerUnion<VarTemplateDecl *,
- VarTemplatePartialSpecializationDecl *>
- Specialized = VTSD->getSpecializedTemplateOrPartial();
- if (auto *VTPSD =
- Specialized.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
- if (VTPSD->isMemberSpecialization())
- return Done();
- } else {
- auto *VTD = Specialized.get<VarTemplateDecl *>();
- if (VTD->isMemberSpecialization())
- return Done();
- }
- return UseNextDecl(VTSD);
- }
-
- Decl *VisitImplicitConceptSpecializationDecl(
- ImplicitConceptSpecializationDecl *ICSD) {
- AddOuterTemplateArguments(ICSD, ICSD->getTemplateArguments(),
- /*Final=*/false);
- return UseNextDecl(ICSD);
}
- Decl *VisitDecl(Decl *D) {
- if (D->isFileContextDecl())
- return Done();
-
- if (isa<DeclContext>(D))
- RelativeToPrimary = false;
-
- return UseNextDecl(D);
- }
+ return Response::UseNextDecl(Rec);
+}
- Decl *Visit(Decl *D) {
- if (TemplateDecl *TD = D->getDescribedTemplate())
- D = TD;
- return DeclVisitor::Visit(D);
- }
-};
+Response HandleImplicitConceptSpecializationDecl(
+ const ImplicitConceptSpecializationDecl *CSD,
+ MultiLevelTemplateArgumentList &Result) {
+ Result.addOuterTemplateArguments(
+ const_cast<ImplicitConceptSpecializationDecl *>(CSD),
+ CSD->getTemplateArguments(),
+ /*Final=*/false);
+ return Response::UseNextDecl(CSD);
+}
+Response HandleGenericDeclContext(const Decl *CurDecl) {
+ return Response::UseNextDecl(CurDecl);
+}
+} // namespace TemplateInstArgsHelpers
} // namespace
MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
const NamedDecl *ND, const DeclContext *DC, bool Final,
std::optional<ArrayRef<TemplateArgument>> Innermost, bool RelativeToPrimary,
- bool ForConstraintInstantiation) {
+ const FunctionDecl *Pattern, bool ForConstraintInstantiation,
+ bool SkipForSpecialization, bool ForDefaultArgumentSubstitution) {
assert((ND || DC) && "Can't find arguments for a decl if one isn't provided");
// Accumulate the set of template argument lists in this structure.
MultiLevelTemplateArgumentList Result;
+
+ using namespace TemplateInstArgsHelpers;
const Decl *CurDecl = ND;
if (!CurDecl)
CurDecl = Decl::castFromDeclContext(DC);
- TemplateInstantiationArgumentCollecter Collecter(
- *this, Result, Innermost, RelativeToPrimary, ForConstraintInstantiation);
- do {
- CurDecl = Collecter.Visit(const_cast<Decl *>(CurDecl));
- } while (CurDecl);
+ if (Innermost) {
+ Result.addOuterTemplateArguments(const_cast<NamedDecl *>(ND), *Innermost,
+ Final);
+ // Populate placeholder template arguments for TemplateTemplateParmDecls.
+ // This is essential for the case e.g.
+ //
+ // template <class> concept Concept = false;
+ // template <template <Concept C> class T> void foo(T<int>)
+ //
+ // where parameter C has a depth of 1 but the substituting argument `int`
+ // has a depth of 0.
+ if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl))
+ HandleDefaultTempArgIntoTempTempParam(TTP, Result);
+ CurDecl = Response::UseNextDecl(CurDecl).NextDecl;
+ }
+
+ while (!CurDecl->isFileContextDecl()) {
+ Response R;
+ if (const auto *VarTemplSpec =
+ dyn_cast<VarTemplateSpecializationDecl>(CurDecl)) {
+ R = HandleVarTemplateSpec(VarTemplSpec, Result, SkipForSpecialization);
+ } else if (const auto *PartialClassTemplSpec =
+ dyn_cast<ClassTemplatePartialSpecializationDecl>(CurDecl)) {
+ R = HandlePartialClassTemplateSpec(PartialClassTemplSpec, Result,
+ SkipForSpecialization);
+ } else if (const auto *ClassTemplSpec =
+ dyn_cast<ClassTemplateSpecializationDecl>(CurDecl)) {
+ R = HandleClassTemplateSpec(ClassTemplSpec, Result,
+ SkipForSpecialization);
+ } else if (const auto *Function = dyn_cast<FunctionDecl>(CurDecl)) {
+ R = HandleFunction(*this, Function, Result, Pattern, RelativeToPrimary,
+ ForConstraintInstantiation,
+ ForDefaultArgumentSubstitution);
+ } else if (const auto *Rec = dyn_cast<CXXRecordDecl>(CurDecl)) {
+ R = HandleRecordDecl(*this, Rec, Result, Context,
+ ForConstraintInstantiation);
+ } else if (const auto *CSD =
+ dyn_cast<ImplicitConceptSpecializationDecl>(CurDecl)) {
+ R = HandleImplicitConceptSpecializationDecl(CSD, Result);
+ } else if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(CurDecl)) {
+ R = HandleFunctionTemplateDecl(FTD, Result);
+ } else if (const auto *CTD = dyn_cast<ClassTemplateDecl>(CurDecl)) {
+ R = Response::ChangeDecl(CTD->getLexicalDeclContext());
+ } else if (!isa<DeclContext>(CurDecl)) {
+ R = Response::DontClearRelativeToPrimaryNextDecl(CurDecl);
+ if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl)) {
+ R = HandleDefaultTempArgIntoTempTempParam(TTP, Result);
+ }
+ } else {
+ R = HandleGenericDeclContext(CurDecl);
+ }
+
+ if (R.IsDone)
+ return Result;
+ if (R.ClearRelativeToPrimary)
+ RelativeToPrimary = false;
+ assert(R.NextDecl);
+ CurDecl = R.NextDecl;
+ }
+
return Result;
}
@@ -1662,8 +1672,10 @@ namespace {
CXXRecordDecl::LambdaDependencyKind
ComputeLambdaDependency(LambdaScopeInfo *LSI) {
- if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl(getSema());
- TypeAlias && isLambdaEnclosedByTypeAliasDecl(
+ if (auto TypeAlias =
+ TemplateInstArgsHelpers::getEnclosingTypeAliasTemplateDecl(
+ getSema());
+ TypeAlias && TemplateInstArgsHelpers::isLambdaEnclosedByTypeAliasDecl(
LSI->CallOperator, TypeAlias.PrimaryTypeAliasDecl)) {
unsigned TypeAliasDeclDepth = TypeAlias.Template->getTemplateDepth();
if (TypeAliasDeclDepth >= TemplateArgs.getNumSubstitutedLevels())
@@ -1702,8 +1714,8 @@ namespace {
// RecoveryExpr that wraps the uninstantiated default argument so
// that downstream diagnostics are omitted.
ExprResult ErrorResult = SemaRef.CreateRecoveryExpr(
- UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(), {UninstExpr},
- UninstExpr->getType());
+ UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(),
+ { UninstExpr }, UninstExpr->getType());
if (ErrorResult.isUsable())
PVD->setDefaultArg(ErrorResult.get());
}
@@ -4097,31 +4109,31 @@ getPatternForClassTemplateSpecialization(
CXXRecordDecl *Pattern = nullptr;
Specialized = ClassTemplateSpec->getSpecializedTemplateOrPartial();
- if (auto *CTD = Specialized.dyn_cast<ClassTemplateDecl *>()) {
- while (true) {
- CTD = CTD->getMostRecentDecl();
- if (CTD->isMemberSpecialization())
- break;
- if (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate())
- CTD = NewCTD;
- else
+ if (auto *PartialSpec =
+ Specialized.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
+ // Instantiate using the best class template partial specialization.
+ while (PartialSpec->getInstantiatedFromMember()) {
+ // If we've found an explicit specialization of this class template,
+ // stop here and use that as the pattern.
+ if (PartialSpec->isMemberSpecialization())
break;
+
+ PartialSpec = PartialSpec->getInstantiatedFromMember();
}
- Pattern = CTD->getTemplatedDecl();
- } else if (auto *CTPSD =
- Specialized
- .dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
- while (true) {
- CTPSD = CTPSD->getMostRecentDecl();
- if (CTPSD->isMemberSpecialization())
- break;
- if (auto *NewCTPSD = CTPSD->getInstantiatedFromMemberTemplate())
- CTPSD = NewCTPSD;
- else
+ Pattern = PartialSpec;
+ } else {
+ ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate();
+ while (Template->getInstantiatedFromMemberTemplate()) {
+ // If we've found an explicit specialization of this class template,
+ // stop here and use that as the pattern.
+ if (Template->isMemberSpecialization())
break;
+
+ Template = Template->getInstantiatedFromMemberTemplate();
}
- Pattern = CTPSD;
+ Pattern = Template->getTemplatedDecl();
}
+
return Pattern;
}
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 74f2152e441e18..34558e1a005d5a 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -12,7 +12,6 @@
#include "TreeTransform.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/ASTLambda.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclVisitor.h"
@@ -4686,36 +4685,6 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
ParmVarDecl *Param) {
assert(Param->hasUninstantiatedDefaultArg());
- NamedDecl *Pattern = FD;
- std::optional<ArrayRef<TemplateArgument>> Innermost;
-
- // C++ [dcl.fct.default]p4
- // For non-template functions, default arguments can be added in later
- // declarations of a function that inhabit the same scope.
- //
- // C++ [dcl.fct.default]p6
- // Except for member functions of templated classes, the default arguments
- // in a member function definition that appears outside of the class
- // definition are added to the set of default arguments provided by the
- // member function declaration in the class definition; the program is
- // ill-formed if a default constructor, copy or move constructor, or copy
- // or move assignment operator is so declared. Default arguments for a
- // member function of a templated class shall be specified on the initial
- // declaration of the member function within the templated class.
- //
- // We need to collect the template arguments from the context of the function
- // where the default argument was defined. For a specialization of a function
- // template explicitly specialized for an implicit instantiation of a class
- // template, that context is the (implicitly instantiated) declaration in the
- // definition of the class template specialization.
- if (FD->isCXXClassMember() &&
- !isGenericLambdaCallOperatorOrStaticInvokerSpecialization(FD)) {
- if (FunctionTemplateDecl *FTD = FD->getPrimaryTemplate()) {
- Pattern = FTD->getFirstDecl();
- Innermost = FD->getTemplateSpecializationArgs()->asArray();
- }
- }
-
// Instantiate the expression.
//
// FIXME: Pass in a correct Pattern argument, otherwise
@@ -4733,10 +4702,12 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
//
// template<typename T>
// A<T> Foo(int a = A<T>::FooImpl());
- MultiLevelTemplateArgumentList TemplateArgs =
- getTemplateInstantiationArgs(Pattern, Pattern->getLexicalDeclContext(),
- /*Final=*/false, Innermost,
- /*RelativeToPrimary=*/true);
+ MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
+ FD, FD->getLexicalDeclContext(),
+ /*Final=*/false, /*Innermost=*/std::nullopt,
+ /*RelativeToPrimary=*/true, /*Pattern=*/nullptr,
+ /*ForConstraintInstantiation=*/false, /*SkipForSpecialization=*/false,
+ /*ForDefaultArgumentSubstitution=*/true);
if (SubstDefaultArgument(CallLoc, Param, TemplateArgs, /*ForCallExpr*/ true))
return true;
@@ -4777,7 +4748,7 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
MultiLevelTemplateArgumentList TemplateArgs =
getTemplateInstantiationArgs(Decl, Decl->getLexicalDeclContext(),
/*Final=*/false, /*Innermost=*/std::nullopt,
- /*RelativeToPrimary=*/true);
+ /*RelativeToPrimary*/ true);
// FIXME: We can't use getTemplateInstantiationPattern(false) in general
// here, because for a non-defining friend declaration in a class template,
@@ -5225,7 +5196,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
SetDeclDefaulted(Function, PatternDecl->getLocation());
} else {
MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
- Function, Function->getLexicalDeclContext());
+ Function, Function->getLexicalDeclContext(), /*Final=*/false,
+ /*Innermost=*/std::nullopt, false, PatternDecl);
// Substitute into the qualifier; we can get a substitution failure here
// through evil use of alias templates.
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 5c4f8d0e9c46cd..e638129897692f 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -10003,8 +10003,7 @@ void ASTReader::finishPendingActions() {
auto RTD = cast<RedeclarableTemplateDecl>(D)->getCanonicalDecl();
for (auto *R = getMostRecentExistingDecl(RTD); R; R = R->getPreviousDecl())
- cast<RedeclarableTemplateDecl>(R)->setCommonPtr(
- RTD->getCommonPtrInternal());
+ cast<RedeclarableTemplateDecl>(R)->Common = RTD->Common;
}
PendingDefinitions.clear();
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 1ccc810f415eb4..7cead2728ca938 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -2416,13 +2416,11 @@ ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
// Make sure we've allocated the Common pointer first. We do this before
// VisitTemplateDecl so that getCommonPtr() can be used during initialization.
RedeclarableTemplateDecl *CanonD = D->getCanonicalDecl();
- if (!CanonD->getCommonPtrInternal()) {
- CanonD->setCommonPtr(CanonD->newCommon(Reader.getContext()));
+ if (!CanonD->Common) {
+ CanonD->Common = CanonD->newCommon(Reader.getContext());
Reader.PendingDefinitions.insert(CanonD);
}
- D->setCommonPtr(CanonD->getCommonPtrInternal());
- if (Record.readInt())
- D->setMemberSpecialization();
+ D->Common = CanonD->Common;
// If this is the first declaration of the template, fill in the information
// for the 'common' pointer.
@@ -2431,6 +2429,8 @@ ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
assert(RTD->getKind() == D->getKind() &&
"InstantiatedFromMemberTemplate kind mismatch");
D->setInstantiatedFromMemberTemplate(RTD);
+ if (Record.readInt())
+ D->setMemberSpecialization();
}
}
@@ -2562,12 +2562,12 @@ void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl(
D->TemplateParams = Params;
RedeclarableResult Redecl = VisitClassTemplateSpecializationDeclImpl(D);
- D->InstantiatedFromMember.setInt(Record.readInt());
// These are read/set from/to the first declaration.
if (ThisDeclID == Redecl.getFirstID()) {
D->InstantiatedFromMember.setPointer(
- readDeclAs<ClassTemplatePartialSpecializationDecl>());
+ readDeclAs<ClassTemplatePartialSpecializationDecl>());
+ D->InstantiatedFromMember.setInt(Record.readInt());
}
}
@@ -2660,12 +2660,12 @@ void ASTDeclReader::VisitVarTemplatePartialSpecializationDecl(
D->TemplateParams = Params;
RedeclarableResult Redecl = VisitVarTemplateSpecializationDeclImpl(D);
- D->InstantiatedFromMember.setInt(Record.readInt());
// These are read/set from/to the first declaration.
if (ThisDeclID == Redecl.getFirstID()) {
D->InstantiatedFromMember.setPointer(
readDeclAs<VarTemplatePartialSpecializationDecl>());
+ D->InstantiatedFromMember.setInt(Record.readInt());
}
}
@@ -2888,7 +2888,7 @@ void ASTDeclReader::mergeRedeclarableTemplate(RedeclarableTemplateDecl *D,
// If we merged the template with a prior declaration chain, merge the
// common pointer.
// FIXME: Actually merge here, don't just overwrite.
- D->setCommonPtr(D->getCanonicalDecl()->getCommonPtrInternal());
+ D->Common = D->getCanonicalDecl()->Common;
}
/// "Cast" to type T, asserting if we don't have an implicit conversion.
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index f21cbd11b6ab89..b71684569609ac 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -1713,13 +1713,14 @@ void ASTDeclWriter::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) {
void ASTDeclWriter::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
VisitRedeclarable(D);
- Record.push_back(D->isMemberSpecialization());
-
// Emit data to initialize CommonOrPrev before VisitTemplateDecl so that
// getCommonPtr() can be used while this is still initializing.
- if (D->isFirstDecl())
+ if (D->isFirstDecl()) {
// This declaration owns the 'common' pointer, so serialize that data now.
Record.AddDeclRef(D->getInstantiatedFromMemberTemplate());
+ if (D->getInstantiatedFromMemberTemplate())
+ Record.push_back(D->isMemberSpecialization());
+ }
VisitTemplateDecl(D);
Record.push_back(D->getIdentifierNamespace());
@@ -1805,10 +1806,11 @@ void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl(
VisitClassTemplateSpecializationDecl(D);
- Record.push_back(D->isMemberSpecialization());
// These are read/set from/to the first declaration.
- if (D->isFirstDecl())
+ if (D->getPreviousDecl() == nullptr) {
Record.AddDeclRef(D->getInstantiatedFromMember());
+ Record.push_back(D->isMemberSpecialization());
+ }
Code = serialization::DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION;
}
@@ -1872,11 +1874,12 @@ void ASTDeclWriter::VisitVarTemplatePartialSpecializationDecl(
Record.AddTemplateParameterList(D->getTemplateParameters());
VisitVarTemplateSpecializationDecl(D);
- Record.push_back(D->isMemberSpecialization());
// These are read/set from/to the first declaration.
- if (D->isFirstDecl())
+ if (D->getPreviousDecl() == nullptr) {
Record.AddDeclRef(D->getInstantiatedFromMember());
+ Record.push_back(D->isMemberSpecialization());
+ }
Code = serialization::DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION;
}
diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp
deleted file mode 100644
index 70064f867e18e3..00000000000000
--- a/clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp
+++ /dev/null
@@ -1,175 +0,0 @@
-// RUN: %clang_cc1 -std=c++20 -verify %s
-// expected-no-diagnostics
-
-template<typename T>
-concept D = true;
-
-template<typename T>
-struct A {
- template<typename U, bool V>
- void f() requires V;
-
- template<>
- void f<short, true>();
-
- template<D U>
- void g();
-
- template<typename U, bool V> requires V
- struct B;
-
- template<typename U, bool V> requires V
- struct B<U*, V>;
-
- template<>
- struct B<short, true>;
-
- template<D U>
- struct C;
-
- template<D U>
- struct C<U*>;
-
- template<typename U, bool V> requires V
- static int x;
-
- template<typename U, bool V> requires V
- static int x<U*, V>;
-
- template<>
- int x<short, true>;
-
- template<D U>
- static int y;
-
- template<D U>
- static int y<U*>;
-};
-
-template<typename T>
-template<typename U, bool V>
-void A<T>::f() requires V { }
-
-template<typename T>
-template<D U>
-void A<T>::g() { }
-
-template<typename T>
-template<typename U, bool V> requires V
-struct A<T>::B { };
-
-template<typename T>
-template<typename U, bool V> requires V
-struct A<T>::B<U*, V> { };
-
-template<typename T>
-template<typename U, bool V> requires V
-struct A<T>::B<U&, V> { };
-
-template<typename T>
-template<D U>
-struct A<T>::C { };
-
-template<typename T>
-template<D U>
-struct A<T>::C<U*> { };
-
-template<typename T>
-template<typename U, bool V> requires V
-int A<T>::x = 0;
-
-template<typename T>
-template<typename U, bool V> requires V
-int A<T>::x<U*, V> = 0;
-
-template<typename T>
-template<typename U, bool V> requires V
-int A<T>::x<U&, V> = 0;
-
-template<typename T>
-template<D U>
-int A<T>::y = 0;
-
-template<typename T>
-template<D U>
-int A<T>::y<U*> = 0;
-
-template<>
-template<typename U, bool V>
-void A<short>::f() requires V;
-
-template<>
-template<>
-void A<short>::f<int, true>();
-
-template<>
-template<>
-void A<void>::f<int, true>();
-
-template<>
-template<D U>
-void A<short>::g();
-
-template<>
-template<typename U, bool V> requires V
-struct A<int>::B;
-
-template<>
-template<>
-struct A<int>::B<int, true>;
-
-template<>
-template<>
-struct A<void>::B<int, true>;
-
-template<>
-template<typename U, bool V> requires V
-struct A<int>::B<U*, V>;
-
-template<>
-template<typename U, bool V> requires V
-struct A<int>::B<U&, V>;
-
-template<>
-template<D U>
-struct A<int>::C;
-
-template<>
-template<D U>
-struct A<int>::C<U*>;
-
-template<>
-template<D U>
-struct A<int>::C<U&>;
-
-template<>
-template<typename U, bool V> requires V
-int A<long>::x;
-
-template<>
-template<>
-int A<long>::x<int, true>;
-
-template<>
-template<>
-int A<void>::x<int, true>;
-
-template<>
-template<typename U, bool V> requires V
-int A<long>::x<U*, V>;
-
-template<>
-template<typename U, bool V> requires V
-int A<long>::x<U&, V>;
-
-template<>
-template<D U>
-int A<long>::y;
-
-template<>
-template<D U>
-int A<long>::y<U*>;
-
-template<>
-template<D U>
-int A<long>::y<U&>;
diff --git a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp
deleted file mode 100644
index 1df449293bad82..00000000000000
--- a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp
+++ /dev/null
@@ -1,178 +0,0 @@
-// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
-
-namespace Undefined {
- template<typename T>
- struct A {
- template<typename U>
- static constexpr int f(); // expected-note {{declared here}}
-
- template<typename U>
- static const int x; // expected-note {{declared here}}
-
- template<typename U>
- static const int x<U*>; // expected-note {{declared here}}
-
- template<typename U>
- struct B; // expected-note {{template is declared here}}
-
- template<typename U>
- struct B<U*>; // expected-note {{template is declared here}}
- };
-
- template<>
- template<typename U>
- constexpr int A<short>::f() {
- return A<long>::f<U>();
- }
-
- template<>
- template<typename U>
- constexpr int A<short>::x = A<long>::x<U>;
-
- template<>
- template<typename U>
- constexpr int A<short>::x<U*> = A<long>::x<U*>;
-
- template<>
- template<typename U>
- struct A<short>::B<U*> {
- static constexpr int y = A<long>::B<U*>::y;
- };
-
- template<>
- template<typename U>
- struct A<short>::B {
- static constexpr int y = A<long>::B<U>::y;
- };
-
- template<>
- template<typename U>
- constexpr int A<long>::f() {
- return 1;
- }
-
- template<>
- template<typename U>
- constexpr int A<long>::x = 1;
-
- template<>
- template<typename U>
- constexpr int A<long>::x<U*> = 2;
-
- template<>
- template<typename U>
- struct A<long>::B {
- static constexpr int y = 1;
- };
-
- template<>
- template<typename U>
- struct A<long>::B<U*> {
- static constexpr int y = 2;
- };
-
- static_assert(A<int>::f<int>() == 0); // expected-error {{static assertion expression is not an integral constant expression}}
- // expected-note at -1 {{undefined function 'f<int>' cannot be used in a constant expression}}
- static_assert(A<int>::x<int> == 0); // expected-error {{static assertion expression is not an integral constant expression}}
- // expected-note at -1 {{initializer of 'x<int>' is unknown}}
- static_assert(A<int>::x<int*> == 0); // expected-error {{static assertion expression is not an integral constant expression}}
- // expected-note at -1 {{initializer of 'x<int *>' is unknown}}
- static_assert(A<int>::B<int>::y == 0); // expected-error {{implicit instantiation of undefined template 'Undefined::A<int>::B<int>'}}
- static_assert(A<int>::B<int*>::y == 0); // expected-error {{implicit instantiation of undefined template 'Undefined::A<int>::B<int *>'}}
-
- static_assert(A<short>::f<int>() == 1);
- static_assert(A<short>::x<int> == 1);
- static_assert(A<short>::x<int*> == 2);
- static_assert(A<short>::B<int>::y == 1);
- static_assert(A<short>::B<int*>::y == 2);
-} // namespace Undefined
-
-namespace Defined {
- template<typename T>
- struct A {
- template<typename U>
- static constexpr int f() {
- return 0;
- };
-
- template<typename U>
- static const int x = 0;
-
- template<typename U>
- static const int x<U*> = 0;
-
- template<typename U>
- struct B {
- static constexpr int y = 0;
- };
-
- template<typename U>
- struct B<U*> {
- static constexpr int y = 0;
- };
- };
-
- template<>
- template<typename U>
- constexpr int A<short>::f() {
- return A<long>::f<U>();
- }
-
- template<>
- template<typename U>
- constexpr int A<short>::x = A<long>::x<U>;
-
- template<>
- template<typename U>
- constexpr int A<short>::x<U*> = A<long>::x<U*>;
-
- template<>
- template<typename U>
- struct A<short>::B<U*> {
- static constexpr int y = A<long>::B<U*>::y;
- };
-
- template<>
- template<typename U>
- struct A<short>::B {
- static constexpr int y = A<long>::B<U>::y;
- };
-
- template<>
- template<typename U>
- constexpr int A<long>::f() {
- return 1;
- }
-
- template<>
- template<typename U>
- constexpr int A<long>::x = 1;
-
- template<>
- template<typename U>
- constexpr int A<long>::x<U*> = 2;
-
- template<>
- template<typename U>
- struct A<long>::B {
- static constexpr int y = 1;
- };
-
- template<>
- template<typename U>
- struct A<long>::B<U*> {
- static constexpr int y = 2;
- };
-
- static_assert(A<int>::f<int>() == 0);
- static_assert(A<int>::x<int> == 0);
- static_assert(A<int>::x<int*> == 0);
- static_assert(A<int>::B<int>::y == 0);
- static_assert(A<int>::B<int*>::y == 0);
-
- static_assert(A<short>::f<int>() == 1);
- static_assert(A<short>::x<int> == 1);
- static_assert(A<short>::x<int*> == 2);
- static_assert(A<short>::B<int>::y == 1);
- static_assert(A<short>::B<int*>::y == 2);
-} // namespace Defined
diff --git a/clang/test/Modules/cxx-templates.cpp b/clang/test/Modules/cxx-templates.cpp
index 44b02ad3ec748c..b7d5741e69af61 100644
--- a/clang/test/Modules/cxx-templates.cpp
+++ b/clang/test/Modules/cxx-templates.cpp
@@ -199,7 +199,9 @@ namespace hidden_specializations {
cls<char*> uk4; // expected-error 1+{{partial specialization of 'cls<T *>' must be imported}} expected-error 1+{{definition of}}
cls<void>::nested_cls unk1; // expected-error 1+{{explicit specialization of 'nested_cls' must be imported}} expected-error 1+{{definition of}}
cls<void>::nested_cls_t<int> unk2; // expected-error 1+{{explicit specialization of 'nested_cls_t' must be imported}} expected-error 1+{{definition of}}
- cls<void>::nested_cls_t<char> unk3; // expected-error 1+{{explicit specialization of 'nested_cls_t' must be imported}} expected-error 1+{{definition of}}
+ // expected-error at cxx-templates-unimported.h:29 {{explicit specialization of 'nested_cls_t' must be imported}}
+ // expected-note at -2 {{in evaluation of exception specification}}
+ cls<void>::nested_cls_t<char> unk3; // expected-error 1+{{explicit specialization of 'nested_cls_t' must be imported}}
// For enums, uses that would trigger instantiations of definitions are not
// allowed.
More information about the cfe-commits
mailing list