[clang] 4da8ac3 - Reapply "[Clang][Sema] Refactor collection of multi-level template argument lists (#106585)" (#111173)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Oct 8 07:14:13 PDT 2024
Author: Krystian Stasiowski
Date: 2024-10-08T10:14:09-04:00
New Revision: 4da8ac34f76e707ab94380b94f616457cfd2cb83
URL: https://github.com/llvm/llvm-project/commit/4da8ac34f76e707ab94380b94f616457cfd2cb83
DIFF: https://github.com/llvm/llvm-project/commit/4da8ac34f76e707ab94380b94f616457cfd2cb83.diff
LOG: Reapply "[Clang][Sema] Refactor collection of multi-level template argument lists (#106585)" (#111173)
Reapplies #106585, fixing an issue where non-dependent names of member
templates appearing prior to that member template being explicitly
specialized for an implicitly instantiated class template specialization
would incorrectly use the definition of the explicitly specialized
member template.
Added:
clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp
clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp
Modified:
clang/docs/ReleaseNotes.rst
clang/include/clang/AST/DeclTemplate.h
clang/include/clang/Sema/Sema.h
clang/lib/AST/Decl.cpp
clang/lib/AST/DeclCXX.cpp
clang/lib/AST/DeclTemplate.cpp
clang/lib/Sema/SemaConcept.cpp
clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaDeclCXX.cpp
clang/lib/Sema/SemaTemplate.cpp
clang/lib/Sema/SemaTemplateDeduction.cpp
clang/lib/Sema/SemaTemplateDeductionGuide.cpp
clang/lib/Sema/SemaTemplateInstantiate.cpp
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
clang/lib/Serialization/ASTReader.cpp
clang/lib/Serialization/ASTReaderDecl.cpp
clang/lib/Serialization/ASTWriterDecl.cpp
clang/test/Modules/cxx-templates.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 21c6e3c98e87a4..bd86fff6dd03fa 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -481,6 +481,9 @@ 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)
Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index 687715a22e9fd3..05739f39d2a496 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -781,15 +781,11 @@ class RedeclarableTemplateDecl : public TemplateDecl,
EntryType *Entry, void *InsertPos);
struct CommonBase {
- CommonBase() : InstantiatedFromMember(nullptr, false) {}
+ CommonBase() {}
/// The template from which this was most
/// directly instantiated (or null).
- ///
- /// The boolean value indicates whether this template
- /// was explicitly specialized.
- llvm::PointerIntPair<RedeclarableTemplateDecl*, 1, bool>
- InstantiatedFromMember;
+ RedeclarableTemplateDecl *InstantiatedFromMember = nullptr;
/// If non-null, points to an array of specializations (including
/// partial specializations) known only by their external declaration IDs.
@@ -809,14 +805,19 @@ class RedeclarableTemplateDecl : public TemplateDecl,
};
/// Pointer to the common data shared by all declarations of this
- /// template.
- mutable CommonBase *Common = nullptr;
+ /// 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(); }
/// 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.
@@ -857,15 +858,12 @@ class RedeclarableTemplateDecl : public TemplateDecl,
/// template<> template<typename T>
/// struct X<int>::Inner { /* ... */ };
/// \endcode
- bool isMemberSpecialization() const {
- return getCommonPtr()->InstantiatedFromMember.getInt();
- }
+ bool isMemberSpecialization() const { return Common.getInt(); }
/// Note that this member template is a specialization.
void setMemberSpecialization() {
- assert(getCommonPtr()->InstantiatedFromMember.getPointer() &&
- "Only member templates can be member template specializations");
- getCommonPtr()->InstantiatedFromMember.setInt(true);
+ assert(!isMemberSpecialization() && "already a member specialization");
+ Common.setInt(true);
}
/// Retrieve the member template from which this template was
@@ -905,12 +903,12 @@ class RedeclarableTemplateDecl : public TemplateDecl,
/// void X<T>::f(T, U);
/// \endcode
RedeclarableTemplateDecl *getInstantiatedFromMemberTemplate() const {
- return getCommonPtr()->InstantiatedFromMember.getPointer();
+ return getCommonPtr()->InstantiatedFromMember;
}
void setInstantiatedFromMemberTemplate(RedeclarableTemplateDecl *TD) {
- assert(!getCommonPtr()->InstantiatedFromMember.getPointer());
- getCommonPtr()->InstantiatedFromMember.setPointer(TD);
+ assert(!getCommonPtr()->InstantiatedFromMember);
+ getCommonPtr()->InstantiatedFromMember = TD;
}
/// Retrieve the "injected" template arguments that correspond to the
@@ -1989,6 +1987,8 @@ 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,6 +2000,8 @@ 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;
@@ -2187,18 +2189,11 @@ class ClassTemplatePartialSpecializationDecl
/// struct X<int>::Inner<T*> { /* ... */ };
/// \endcode
bool isMemberSpecialization() const {
- const auto *First =
- cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
- return First->InstantiatedFromMember.getInt();
+ return InstantiatedFromMember.getInt();
}
/// Note that this member template is a specialization.
- void setMemberSpecialization() {
- auto *First = cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
- assert(First->InstantiatedFromMember.getPointer() &&
- "Only member templates can be member template specializations");
- return First->InstantiatedFromMember.setInt(true);
- }
+ void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); }
/// Retrieves the injected specialization type for this partial
/// specialization. This is not the same as the type-decl-type for
@@ -2268,10 +2263,6 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr());
}
- void setCommonPtr(Common *C) {
- RedeclarableTemplateDecl::Common = C;
- }
-
public:
friend class ASTDeclReader;
@@ -2754,6 +2745,8 @@ 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();
@@ -2765,6 +2758,8 @@ 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;
@@ -2949,18 +2944,11 @@ class VarTemplatePartialSpecializationDecl
/// U* X<int>::Inner<T*> = (T*)(0) + 1;
/// \endcode
bool isMemberSpecialization() const {
- const auto *First =
- cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
- return First->InstantiatedFromMember.getInt();
+ return InstantiatedFromMember.getInt();
}
/// Note that this member template is a specialization.
- void setMemberSpecialization() {
- auto *First = cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
- assert(First->InstantiatedFromMember.getPointer() &&
- "Only member templates can be member template specializations");
- return First->InstantiatedFromMember.setInt(true);
- }
+ void setMemberSpecialization() { return 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 bede971ce0191b..7ff9c2754a6fe0 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, unsigned NumOuterTemplateParamLists,
- TemplateParameterList **OuterTemplateParamLists,
- SkipBodyInfo *SkipBody = nullptr);
+ SourceLocation FriendLoc,
+ ArrayRef<TemplateParameterList *> OuterTemplateParamLists,
+ bool IsMemberSpecialization, SkipBodyInfo *SkipBody = nullptr);
/// Translates template arguments as provided by the parser
/// into template arguments used by semantic analysis.
@@ -11366,7 +11366,8 @@ class Sema final : public SemaBase {
DeclResult ActOnVarTemplateSpecialization(
Scope *S, Declarator &D, TypeSourceInfo *DI, LookupResult &Previous,
SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams,
- StorageClass SC, bool IsPartialSpecialization);
+ StorageClass SC, bool IsPartialSpecialization,
+ bool IsMemberSpecialization);
/// Get the specialization of the given variable template corresponding to
/// the specified argument list, or a null-but-valid result if the arguments
@@ -13017,28 +13018,14 @@ 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, const FunctionDecl *Pattern = nullptr,
- bool ForConstraintInstantiation = false,
- bool SkipForSpecialization = false,
- bool ForDefaultArgumentSubstitution = false);
+ bool RelativeToPrimary = false, bool ForConstraintInstantiation = 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 84ef9f74582ef6..58d11a0312c505 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -2696,21 +2696,27 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const {
if (isTemplateInstantiation(VDTemplSpec->getTemplateSpecializationKind())) {
auto From = VDTemplSpec->getInstantiatedFrom();
if (auto *VTD = From.dyn_cast<VarTemplateDecl *>()) {
- while (!VTD->isMemberSpecialization()) {
- auto *NewVTD = VTD->getInstantiatedFromMemberTemplate();
- if (!NewVTD)
+ while (true) {
+ VTD = VTD->getMostRecentDecl();
+ if (VTD->isMemberSpecialization())
+ break;
+ if (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate())
+ VTD = NewVTD;
+ else
break;
- VTD = NewVTD;
}
return getDefinitionOrSelf(VTD->getTemplatedDecl());
}
if (auto *VTPSD =
From.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
- while (!VTPSD->isMemberSpecialization()) {
- auto *NewVTPSD = VTPSD->getInstantiatedFromMember();
- if (!NewVTPSD)
+ while (true) {
+ VTPSD = VTPSD->getMostRecentDecl();
+ if (VTPSD->isMemberSpecialization())
+ break;
+ if (auto *NewVTPSD = VTPSD->getInstantiatedFromMember())
+ VTPSD = NewVTPSD;
+ else
break;
- VTPSD = NewVTPSD;
}
return getDefinitionOrSelf<VarDecl>(VTPSD);
}
@@ -2719,15 +2725,17 @@ 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 *VarTemplate = VD->getDescribedVarTemplate()) {
- while (!VarTemplate->isMemberSpecialization()) {
- auto *NewVT = VarTemplate->getInstantiatedFromMemberTemplate();
- if (!NewVT)
+ if (VarTemplateDecl *VTD = VD->getDescribedVarTemplate()) {
+ while (true) {
+ VTD = VTD->getMostRecentDecl();
+ if (VTD->isMemberSpecialization())
+ break;
+ if (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate())
+ VTD = NewVTD;
+ else
break;
- VarTemplate = NewVT;
}
-
- return getDefinitionOrSelf(VarTemplate->getTemplatedDecl());
+ return getDefinitionOrSelf(VTD->getTemplatedDecl());
}
if (VD == this)
@@ -4142,11 +4150,14 @@ 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 (!ForDefinition || !Primary->isMemberSpecialization()) {
- auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate();
- if (!NewPrimary)
+ while (true) {
+ Primary = Primary->getMostRecentDecl();
+ if (ForDefinition && Primary->isMemberSpecialization())
+ break;
+ if (auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate())
+ Primary = NewPrimary;
+ else
break;
- Primary = NewPrimary;
}
return getDefinitionOrSelf(Primary->getTemplatedDecl());
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 1364ccc745ba01..cfc7a9a218f251 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -2023,19 +2023,27 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const {
if (auto *TD = dyn_cast<ClassTemplateSpecializationDecl>(this)) {
auto From = TD->getInstantiatedFrom();
if (auto *CTD = From.dyn_cast<ClassTemplateDecl *>()) {
- while (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) {
- if (NewCTD->isMemberSpecialization())
+ while (true) {
+ CTD = CTD->getMostRecentDecl();
+ if (CTD->isMemberSpecialization())
+ break;
+ if (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate())
+ CTD = NewCTD;
+ else
break;
- CTD = NewCTD;
}
return GetDefinitionOrSelf(CTD->getTemplatedDecl());
}
if (auto *CTPSD =
From.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
- while (auto *NewCTPSD = CTPSD->getInstantiatedFromMember()) {
- if (NewCTPSD->isMemberSpecialization())
+ while (true) {
+ CTPSD = CTPSD->getMostRecentDecl();
+ if (CTPSD->isMemberSpecialization())
+ break;
+ if (auto *NewCTPSD = CTPSD->getInstantiatedFromMemberTemplate())
+ CTPSD = NewCTPSD;
+ else
break;
- CTPSD = NewCTPSD;
}
return GetDefinitionOrSelf(CTPSD);
}
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index 6fe817c5ef1c6b..d9b67b7bedf5a5 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 (Common)
- return Common;
+ if (CommonBase *C = getCommonPtrInternal())
+ return C;
// 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 (Prev->Common) {
- Common = Prev->Common;
+ if (CommonBase *C = Prev->getCommonPtrInternal()) {
+ setCommonPtr(C);
break;
}
@@ -326,18 +326,18 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() c
}
// If we never found a common pointer, allocate one now.
- if (!Common) {
+ if (!getCommonPtrInternal()) {
// FIXME: If any of the declarations is from an AST file, we probably
// need an update record to add the common data.
- Common = newCommon(getASTContext());
+ setCommonPtr(newCommon(getASTContext()));
}
// Update any previous declarations we saw with the common pointer.
for (const RedeclarableTemplateDecl *Prev : PrevDecls)
- Prev->Common = Common;
+ Prev->setCommonPtr(getCommonPtrInternal());
- return Common;
+ return getCommonPtrInternal();
}
void RedeclarableTemplateDecl::loadLazySpecializationsImpl() const {
@@ -463,19 +463,17 @@ 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 (!Base::Common)
+ if (!getCommonPtrInternal())
return;
- Common *ThisCommon = static_cast<Common *>(Base::Common);
+ Common *ThisCommon = static_cast<Common *>(getCommonPtrInternal());
Common *PrevCommon = nullptr;
SmallVector<FunctionTemplateDecl *, 8> PreviousDecls;
for (; Prev; Prev = Prev->getPreviousDecl()) {
- if (Prev->Base::Common) {
- PrevCommon = static_cast<Common *>(Prev->Base::Common);
+ if (CommonBase *C = Prev->getCommonPtrInternal()) {
+ PrevCommon = static_cast<Common *>(C);
break;
}
PreviousDecls.push_back(Prev);
@@ -485,7 +483,7 @@ void FunctionTemplateDecl::mergePrevDecl(FunctionTemplateDecl *Prev) {
// use this common pointer.
if (!PrevCommon) {
for (auto *D : PreviousDecls)
- D->Base::Common = ThisCommon;
+ D->setCommonPtr(ThisCommon);
return;
}
@@ -493,7 +491,7 @@ void FunctionTemplateDecl::mergePrevDecl(FunctionTemplateDecl *Prev) {
assert(ThisCommon->Specializations.size() == 0 &&
"Can't merge incompatible declarations!");
- Base::Common = PrevCommon;
+ setCommonPtr(PrevCommon);
}
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 998a148a7d24a1..e36ee062213716 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.getOutermost()
- : ArrayRef<TemplateArgument> {};
+ ? TemplateArgsLists.getInnermost()
+ : ArrayRef<TemplateArgument>{};
Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(),
Sema::InstantiatingTemplate::ConstraintsCheck{},
const_cast<NamedDecl *>(Template), TemplateArgs, TemplateIDRange);
@@ -834,7 +834,6 @@ 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;
@@ -910,15 +909,13 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
// Figure out the to-translation-unit depth for this function declaration for
// the purpose of seeing if they
diff er by constraints. This isn't the same as
// getTemplateDepth, because it includes already instantiated parents.
-static unsigned
-CalculateTemplateDepthForConstraints(Sema &S, const NamedDecl *ND,
- bool SkipForSpecialization = false) {
+static unsigned CalculateTemplateDepthForConstraints(Sema &S,
+ const NamedDecl *ND) {
MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
ND, ND->getLexicalDeclContext(), /*Final=*/false,
/*Innermost=*/std::nullopt,
/*RelativeToPrimary=*/true,
- /*Pattern=*/nullptr,
- /*ForConstraintInstantiation=*/true, SkipForSpecialization);
+ /*ForConstraintInstantiation=*/true);
return MLTAL.getNumLevels();
}
@@ -957,8 +954,7 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
DeclInfo.getDecl(), DeclInfo.getLexicalDeclContext(), /*Final=*/false,
/*Innermost=*/std::nullopt,
/*RelativeToPrimary=*/true,
- /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true,
- /*SkipForSpecialization*/ false);
+ /*ForConstraintInstantiation=*/true);
if (MLTAL.getNumSubstitutedLevels() == 0)
return ConstrExpr;
@@ -1068,16 +1064,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(FD->getDescribedFunctionTemplate() &&
- "Non-function templates don't need to be checked");
+ assert(FTD && "Non-function templates don't need to be checked");
SmallVector<const Expr *, 3> ACs;
- FD->getDescribedFunctionTemplate()->getAssociatedConstraints(ACs);
+ FTD->getAssociatedConstraints(ACs);
- unsigned OldTemplateDepth = CalculateTemplateDepthForConstraints(*this, FD);
+ unsigned OldTemplateDepth = FTD->getTemplateParameters()->getDepth();
for (const Expr *Constraint : ACs)
if (ConstraintExpressionDependsOnEnclosingTemplate(FD, OldTemplateDepth,
Constraint))
@@ -1524,7 +1520,6 @@ 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,
@@ -1805,8 +1800,8 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1,
return false;
}
- unsigned Depth1 = CalculateTemplateDepthForConstraints(*this, D1, true);
- unsigned Depth2 = CalculateTemplateDepthForConstraints(*this, D2, true);
+ unsigned Depth1 = CalculateTemplateDepthForConstraints(*this, D1);
+ unsigned Depth2 = CalculateTemplateDepthForConstraints(*this, D2);
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 4eaa3913f4344a..83d71913f8635e 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->getTemplateParameters(),
- OldTemplate->getTemplateParameters(),
- /*Complain=*/true, TPL_TemplateMatch))
+ if (NewTemplate && !TemplateParameterListsAreEqual(
+ NewTemplate, NewTemplate->getTemplateParameters(),
+ OldTemplate, 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);
+ IsPartialSpecialization, IsMemberSpecialization);
if (Res.isInvalid())
return nullptr;
NewVD = cast<VarDecl>(Res.get());
@@ -7682,6 +7682,10 @@ 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
@@ -8058,12 +8062,6 @@ 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();
}
}
@@ -9870,6 +9868,8 @@ 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) {
@@ -12027,10 +12027,7 @@ 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 &&
- NewTemplateDecl->getInstantiatedFromMemberTemplate()) {
- NewTemplateDecl->setMemberSpecialization();
- assert(OldTemplateDecl->isMemberSpecialization());
+ if (IsMemberSpecialization) {
// Explicit specializations of a member template do not inherit deleted
// status from the parent member template that they are specializing.
if (OldFD->isDeleted()) {
@@ -17092,8 +17089,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.size() - 1,
- TemplateParameterLists.data(), SkipBody);
+ /*FriendLoc*/ SourceLocation(), TemplateParameterLists.drop_back(),
+ isMemberSpecialization, 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 9cb2ed02a3f764..75d82c12e0c1f3 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.size() - 1,
- TempParamLists.data())
+ FriendLoc, TempParamLists.drop_back(),
+ IsMemberSpecialization)
.get();
} else {
// The "template<>" header is extraneous.
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index eeaa1ebd7ba83a..b1a34edba9150b 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -1795,8 +1795,9 @@ DeclResult Sema::CheckClassTemplate(
CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc,
const ParsedAttributesView &Attr, TemplateParameterList *TemplateParams,
AccessSpecifier AS, SourceLocation ModulePrivateLoc,
- SourceLocation FriendLoc, unsigned NumOuterTemplateParamLists,
- TemplateParameterList **OuterTemplateParamLists, SkipBodyInfo *SkipBody) {
+ SourceLocation FriendLoc,
+ ArrayRef<TemplateParameterList *> OuterTemplateParamLists,
+ bool IsMemberSpecialization, SkipBodyInfo *SkipBody) {
assert(TemplateParams && TemplateParams->size() > 0 &&
"No template parameters");
assert(TUK != TagUseKind::Reference &&
@@ -1984,19 +1985,6 @@ 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,
@@ -2011,30 +1999,6 @@ 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
@@ -2046,23 +2010,6 @@ 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.
@@ -2089,10 +2036,8 @@ DeclResult Sema::CheckClassTemplate(
PrevClassTemplate->getTemplatedDecl() : nullptr,
/*DelayTypeCreation=*/true);
SetNestedNameSpecifier(*this, NewClass, SS);
- if (NumOuterTemplateParamLists > 0)
- NewClass->setTemplateParameterListsInfo(
- Context,
- llvm::ArrayRef(OuterTemplateParamLists, NumOuterTemplateParamLists));
+ if (!OuterTemplateParamLists.empty())
+ NewClass->setTemplateParameterListsInfo(Context, OuterTemplateParamLists);
// Add alignment attributes if necessary; these attributes are checked when
// the ASTContext lays out the structure.
@@ -2105,7 +2050,10 @@ 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);
@@ -2120,12 +2068,6 @@ 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())
@@ -2135,8 +2077,62 @@ DeclResult Sema::CheckClassTemplate(
NewClass->setLexicalDeclContext(CurContext);
NewTemplate->setLexicalDeclContext(CurContext);
- if (TUK == TagUseKind::Definition && (!SkipBody || !SkipBody->ShouldSkip))
- NewClass->startDefinition();
+ // 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();
+ }
ProcessDeclAttributeList(S, NewClass, Attr);
ProcessAPINotes(NewClass);
@@ -4133,7 +4129,8 @@ void Sema::CheckDeductionGuideTemplate(FunctionTemplateDecl *TD) {
DeclResult Sema::ActOnVarTemplateSpecialization(
Scope *S, Declarator &D, TypeSourceInfo *DI, LookupResult &Previous,
SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams,
- StorageClass SC, bool IsPartialSpecialization) {
+ StorageClass SC, bool IsPartialSpecialization,
+ bool IsMemberSpecialization) {
// D must be variable template id.
assert(D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId &&
"Variable template specialization is declared with a template id.");
@@ -4251,17 +4248,16 @@ 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
@@ -5779,9 +5775,7 @@ bool Sema::CheckTemplateArgumentList(
MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(
Template, NewContext, /*Final=*/false, CanonicalConverted,
- /*RelativeToPrimary=*/true,
- /*Pattern=*/nullptr,
- /*ForConceptInstantiation=*/true);
+ /*RelativeToPrimary=*/true, /*ForConceptInstantiation=*/true);
if (EnsureTemplateArgumentListConstraints(
Template, MLTAL,
SourceRange(TemplateLoc, TemplateArgs.getRAngleLoc()))) {
@@ -8452,15 +8446,12 @@ 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.size() - 1,
- TemplateParameterLists.data());
+ return CheckClassTemplate(
+ S, TagSpec, TUK, KWLoc, SS, ClassTemplate->getIdentifier(),
+ TemplateNameLoc, Attr, TemplateParams, AS_none,
+ /*ModulePrivateLoc=*/SourceLocation(),
+ /*FriendLoc*/ SourceLocation(), TemplateParameterLists.drop_back(),
+ isMemberSpecialization);
}
// Create a new class template partial specialization declaration node.
@@ -8470,6 +8461,11 @@ 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()) {
@@ -8481,11 +8477,6 @@ 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
@@ -11284,8 +11275,8 @@ class ExplicitSpecializationVisibilityChecker {
template<typename TemplDecl>
void checkTemplate(TemplDecl *TD) {
- if (TD->isMemberSpecialization()) {
- if (!CheckMemberSpecialization(TD))
+ if (TD->getMostRecentDecl()->isMemberSpecialization()) {
+ if (!CheckMemberSpecialization(TD->getMostRecentDecl()))
diagnose(TD->getMostRecentDecl(), false);
}
}
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index ce3317db5a8202..8e80ab730ac342 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3197,20 +3197,6 @@ 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
@@ -3221,23 +3207,10 @@ 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,
- /*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);
+ Template, Template->getDeclContext(), /*Final=*/false,
+ /*Innermost=*/CanonicalDeducedArgs, /*RelativeToPrimary=*/true,
+ /*ForConstraintInstantiation=*/true);
if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL,
Info.getLocation(),
diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index 545da21183c3c4..ca93c840f03215 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> TemplateArgsForBuildingRC(
+ SmallVector<TemplateArgument> InnerArgsForBuildingRC(
F->getTemplateParameters()->size());
// Transform the transformed template args
MultiLevelTemplateArgumentList Args;
@@ -778,33 +778,30 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
NamedDecl *TP = F->getTemplateParameters()->getParam(Index);
MultiLevelTemplateArgumentList Args;
Args.setKind(TemplateSubstitutionKind::Rewrite);
- Args.addOuterTemplateArguments(TemplateArgsForBuildingRC);
+ Args.addOuterTemplateArguments(InnerArgsForBuildingRC);
// 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(TemplateArgsForBuildingRC[Index].isNull());
- TemplateArgsForBuildingRC[Index] =
- Context.getInjectedTemplateArg(NewParam);
+ assert(InnerArgsForBuildingRC[Index].isNull());
+ InnerArgsForBuildingRC[Index] = Context.getInjectedTemplateArg(NewParam);
continue;
}
TemplateArgumentLoc Input =
SemaRef.getTrivialTemplateArgumentLoc(D, QualType(), SourceLocation{});
TemplateArgumentLoc Output;
if (!SemaRef.SubstTemplateArgument(Input, Args, Output)) {
- assert(TemplateArgsForBuildingRC[Index].isNull() &&
+ assert(InnerArgsForBuildingRC[Index].isNull() &&
"InstantiatedArgs must be null before setting");
- TemplateArgsForBuildingRC[Index] = Output.getArgument();
+ InnerArgsForBuildingRC[Index] = Output.getArgument();
}
}
- // 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);
+ // A list of template arguments for transforming the require-clause using
+ // the transformed template arguments as the template argument list of F.
+ //
// 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.
@@ -827,25 +824,15 @@ 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.
- // 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);
- }
+ MultiLevelTemplateArgumentList ArgsForBuildingRC =
+ SemaRef.getTemplateInstantiationArgs(F, F->getLexicalDeclContext(),
+ /*Final=*/false,
+ /*Innermost=*/InnerArgsForBuildingRC,
+ /*RelativeToPrimary=*/true,
+ /*ForConstraintInstantiation=*/true);
+ ArgsForBuildingRC.setKind(clang::TemplateSubstitutionKind::Rewrite);
ExprResult E = SemaRef.SubstExpr(RC, ArgsForBuildingRC);
if (E.isInvalid())
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 4ce47d8c1ee761..f2007fc5d85a50 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -52,38 +52,6 @@ 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.
@@ -171,374 +139,396 @@ bool isLambdaEnclosedByTypeAliasDecl(
.TraverseType(Underlying);
}
-// 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();
+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);
}
- return Response::DontClearRelativeToPrimaryNextDecl(VarTemplSpec);
-}
-// 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 *ChangeDecl(const DeclContext *DC) {
+ return ChangeDecl(Decl::castFromDeclContext(DC));
+ }
-Response HandlePartialClassTemplateSpec(
- const ClassTemplatePartialSpecializationDecl *PartialClassTemplSpec,
- MultiLevelTemplateArgumentList &Result, bool SkipForSpecialization) {
- if (!SkipForSpecialization)
- Result.addOuterRetainedLevels(PartialClassTemplSpec->getTemplateDepth());
- return Response::Done();
-}
+ Decl *UseNextDecl(const Decl *D) { return ChangeDecl(D->getDeclContext()); }
-// 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();
+ void AddInnermostTemplateArguments(const Decl *D) {
+ assert(Innermost);
+ Result.addOuterTemplateArguments(const_cast<Decl *>(D), *Innermost,
+ /*Final=*/false);
+ Innermost.reset();
+ }
- if (!SkipForSpecialization)
- Result.addOuterTemplateArguments(
- const_cast<ClassTemplateSpecializationDecl *>(ClassTemplSpec),
- ClassTemplSpec->getTemplateInstantiationArgs().asArray(),
- /*Final=*/false);
+ void AddOuterTemplateArguments(const Decl *D, ArrayRef<TemplateArgument> Args,
+ bool Final) {
+ Result.addOuterTemplateArguments(const_cast<Decl *>(D), Args, Final);
+ }
- // 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());
+ 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();
}
- return Response::UseNextDecl(ClassTemplSpec);
-}
-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 *VisitFunctionTemplateDecl(FunctionTemplateDecl *FTD) {
+ assert(
+ (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
+ "outer template not instantiated?");
+
+ if (Innermost)
+ AddInnermostTemplateArguments(FTD);
+ else if (ForConstraintInstantiation)
+ AddOuterTemplateArguments(FTD, FTD->getInjectedTemplateArgs(),
+ /*Final=*/false);
+
+ if (FTD->isMemberSpecialization())
+ return Done();
- 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()) {
+ if (FTD->getFriendObjectKind())
+ return ChangeDecl(FTD->getLexicalDeclContext());
+ return UseNextDecl(FTD);
+ }
+
+ Decl *VisitVarTemplateDecl(VarTemplateDecl *VTD) {
assert(
(ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
- "Outer template not instantiated?");
+ "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);
}
- // 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 *VisitVarTemplatePartialSpecializationDecl(
+ VarTemplatePartialSpecializationDecl *VTPSD) {
+ 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);
}
- if (ForConstraintInstantiation && Function->getFriendObjectKind())
- return Response::ChangeDecl(Function->getLexicalDeclContext());
- return Response::UseNextDecl(Function);
-}
+ Decl *VisitClassTemplateDecl(ClassTemplateDecl *CTD) {
+ assert(
+ (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
+ "outer template not instantiated?");
-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);
- }
- }
+ if (Innermost)
+ AddInnermostTemplateArguments(CTD);
+ else if (ForConstraintInstantiation)
+ AddOuterTemplateArguments(CTD, CTD->getInjectedTemplateArgs(),
+ /*Final=*/false);
- NNS = NNS->getPrefix();
- }
+ if (CTD->isMemberSpecialization())
+ return Done();
+
+ if (CTD->getFriendObjectKind())
+ return ChangeDecl(CTD->getLexicalDeclContext());
+ return UseNextDecl(CTD);
}
- return Response::ChangeDecl(FTD->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);
-Response HandleRecordDecl(Sema &SemaRef, const CXXRecordDecl *Rec,
- MultiLevelTemplateArgumentList &Result,
- ASTContext &Context,
- bool ForConstraintInstantiation) {
- if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) {
+ if (CTPSD->isMemberSpecialization())
+ return Done();
+
+ return UseNextDecl(CTPSD);
+ }
+
+ Decl *VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *TATD) {
assert(
(ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
- "Outer template not instantiated?");
- if (ClassTemplate->isMemberSpecialization())
- return Response::Done();
- if (ForConstraintInstantiation)
- Result.addOuterTemplateArguments(const_cast<CXXRecordDecl *>(Rec),
- ClassTemplate->getInjectedTemplateArgs(),
- /*Final=*/false);
+ "outer template not instantiated?");
+ if (Innermost)
+ AddInnermostTemplateArguments(TATD);
+ else if (ForConstraintInstantiation)
+ AddOuterTemplateArguments(TATD, TATD->getInjectedTemplateArgs(),
+ /*Final=*/false);
+
+ return UseNextDecl(TATD);
}
- 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 *VisitConceptDecl(ConceptDecl *CD) {
+ assert(
+ (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
+ "outer template not instantiated?");
+ if (Innermost)
+ AddInnermostTemplateArguments(CD);
+
+ return UseNextDecl(CD);
+ }
+
+ 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);
}
- // 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());
+ 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());
+ }
}
}
+
+ return UseNextDecl(RD);
}
- return Response::UseNextDecl(Rec);
-}
+ 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);
-Response HandleImplicitConceptSpecializationDecl(
- const ImplicitConceptSpecializationDecl *CSD,
- MultiLevelTemplateArgumentList &Result) {
- Result.addOuterTemplateArguments(
- const_cast<ImplicitConceptSpecializationDecl *>(CSD),
- CSD->getTemplateArguments(),
- /*Final=*/false);
- return Response::UseNextDecl(CSD);
-}
+ // 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);
+ }
+
+ Decl *Visit(Decl *D) {
+ if (TemplateDecl *TD = D->getDescribedTemplate())
+ D = TD;
+ return DeclVisitor::Visit(D);
+ }
+};
-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,
- const FunctionDecl *Pattern, bool ForConstraintInstantiation,
- bool SkipForSpecialization, bool ForDefaultArgumentSubstitution) {
+ bool ForConstraintInstantiation) {
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);
- 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;
- }
-
+ TemplateInstantiationArgumentCollecter Collecter(
+ *this, Result, Innermost, RelativeToPrimary, ForConstraintInstantiation);
+ do {
+ CurDecl = Collecter.Visit(const_cast<Decl *>(CurDecl));
+ } while (CurDecl);
return Result;
}
@@ -1687,10 +1677,8 @@ namespace {
CXXRecordDecl::LambdaDependencyKind
ComputeLambdaDependency(LambdaScopeInfo *LSI) {
- if (auto TypeAlias =
- TemplateInstArgsHelpers::getEnclosingTypeAliasTemplateDecl(
- getSema());
- TypeAlias && TemplateInstArgsHelpers::isLambdaEnclosedByTypeAliasDecl(
+ if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl(getSema());
+ TypeAlias && isLambdaEnclosedByTypeAliasDecl(
LSI->CallOperator, TypeAlias.PrimaryTypeAliasDecl)) {
unsigned TypeAliasDeclDepth = TypeAlias.Template->getTemplateDepth();
if (TypeAliasDeclDepth >= TemplateArgs.getNumSubstitutedLevels())
@@ -1729,8 +1717,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());
}
@@ -4124,31 +4112,31 @@ getPatternForClassTemplateSpecialization(
CXXRecordDecl *Pattern = nullptr;
Specialized = ClassTemplateSpec->getSpecializedTemplateOrPartial();
- 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())
+ if (auto *CTD = Specialized.dyn_cast<ClassTemplateDecl *>()) {
+ while (true) {
+ CTD = CTD->getMostRecentDecl();
+ if (CTD->isMemberSpecialization())
+ break;
+ if (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate())
+ CTD = NewCTD;
+ else
break;
-
- PartialSpec = PartialSpec->getInstantiatedFromMember();
}
- 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())
+ 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
break;
-
- Template = Template->getInstantiatedFromMemberTemplate();
}
- Pattern = Template->getTemplatedDecl();
+ Pattern = CTPSD;
}
-
return Pattern;
}
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 1c35c7d288e325..d29434486dcb06 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -12,6 +12,7 @@
#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"
@@ -4685,6 +4686,36 @@ 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
@@ -4702,12 +4733,10 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
//
// template<typename T>
// A<T> Foo(int a = A<T>::FooImpl());
- MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
- FD, FD->getLexicalDeclContext(),
- /*Final=*/false, /*Innermost=*/std::nullopt,
- /*RelativeToPrimary=*/true, /*Pattern=*/nullptr,
- /*ForConstraintInstantiation=*/false, /*SkipForSpecialization=*/false,
- /*ForDefaultArgumentSubstitution=*/true);
+ MultiLevelTemplateArgumentList TemplateArgs =
+ getTemplateInstantiationArgs(Pattern, Pattern->getLexicalDeclContext(),
+ /*Final=*/false, Innermost,
+ /*RelativeToPrimary=*/true);
if (SubstDefaultArgument(CallLoc, Param, TemplateArgs, /*ForCallExpr*/ true))
return true;
@@ -4748,7 +4777,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,
@@ -5186,8 +5215,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
SetDeclDefaulted(Function, PatternDecl->getLocation());
} else {
MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
- Function, Function->getLexicalDeclContext(), /*Final=*/false,
- /*Innermost=*/std::nullopt, false, PatternDecl);
+ Function, Function->getLexicalDeclContext());
// 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 97b79bd1381c02..4a20dfc09cd061 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -10003,7 +10003,8 @@ void ASTReader::finishPendingActions() {
auto RTD = cast<RedeclarableTemplateDecl>(D)->getCanonicalDecl();
for (auto *R = getMostRecentExistingDecl(RTD); R; R = R->getPreviousDecl())
- cast<RedeclarableTemplateDecl>(R)->Common = RTD->Common;
+ cast<RedeclarableTemplateDecl>(R)->setCommonPtr(
+ RTD->getCommonPtrInternal());
}
PendingDefinitions.clear();
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 7cead2728ca938..1ccc810f415eb4 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -2416,11 +2416,13 @@ 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->Common) {
- CanonD->Common = CanonD->newCommon(Reader.getContext());
+ if (!CanonD->getCommonPtrInternal()) {
+ CanonD->setCommonPtr(CanonD->newCommon(Reader.getContext()));
Reader.PendingDefinitions.insert(CanonD);
}
- D->Common = CanonD->Common;
+ D->setCommonPtr(CanonD->getCommonPtrInternal());
+ if (Record.readInt())
+ D->setMemberSpecialization();
// If this is the first declaration of the template, fill in the information
// for the 'common' pointer.
@@ -2429,8 +2431,6 @@ 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>());
- D->InstantiatedFromMember.setInt(Record.readInt());
+ readDeclAs<ClassTemplatePartialSpecializationDecl>());
}
}
@@ -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->Common = D->getCanonicalDecl()->Common;
+ D->setCommonPtr(D->getCanonicalDecl()->getCommonPtrInternal());
}
/// "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 b71684569609ac..f21cbd11b6ab89 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -1713,14 +1713,13 @@ 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());
@@ -1806,11 +1805,10 @@ void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl(
VisitClassTemplateSpecializationDecl(D);
+ Record.push_back(D->isMemberSpecialization());
// These are read/set from/to the first declaration.
- if (D->getPreviousDecl() == nullptr) {
+ if (D->isFirstDecl())
Record.AddDeclRef(D->getInstantiatedFromMember());
- Record.push_back(D->isMemberSpecialization());
- }
Code = serialization::DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION;
}
@@ -1874,12 +1872,11 @@ 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->getPreviousDecl() == nullptr) {
+ if (D->isFirstDecl())
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
new file mode 100644
index 00000000000000..70064f867e18e3
--- /dev/null
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp
@@ -0,0 +1,175 @@
+// 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
new file mode 100644
index 00000000000000..1df449293bad82
--- /dev/null
+++ b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp
@@ -0,0 +1,178 @@
+// 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 953fc0d9e867c4..da5fc6ba4cea9a 100644
--- a/clang/test/Modules/cxx-templates.cpp
+++ b/clang/test/Modules/cxx-templates.cpp
@@ -190,9 +190,7 @@ 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}}
- // 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}}
+ cls<void>::nested_cls_t<char> unk3; // expected-error 1+{{explicit specialization of 'nested_cls_t' must be imported}} expected-error 1+{{definition of}}
// For enums, uses that would trigger instantiations of definitions are not
// allowed.
More information about the cfe-commits
mailing list