summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2019-05-02 00:49:14 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2019-05-02 00:49:14 +0000
commit672ad5280a92fdc73cf54e6fc6ec50e73f6aa7d3 (patch)
tree56d21195b68ef956a8c4264da03e75751877d732
parent2d77937455e8f133a9e4df562d91f40a97c59c8c (diff)
Replace ad-hoc tracking of pattern for an instantiated class-scope
explicit function specialization with the MemberSpecializationInfo used everywhere else. Not NFC: the ad-hoc pattern tracking was not being serialized / deserialized properly. That's fixed here. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@359747 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/ASTContext.h10
-rw-r--r--include/clang/AST/ASTNodeTraverser.h11
-rw-r--r--include/clang/AST/Decl.h18
-rw-r--r--include/clang/AST/DeclTemplate.h144
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h6
-rw-r--r--include/clang/Sema/Template.h3
-rw-r--r--lib/AST/ASTContext.cpp21
-rw-r--r--lib/AST/Decl.cpp119
-rw-r--r--lib/AST/DeclTemplate.cpp22
-rw-r--r--lib/Sema/SemaExpr.cpp3
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp5
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp72
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp26
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp13
-rw-r--r--test/PCH/cxx-templates.cpp30
-rw-r--r--test/PCH/cxx-templates.h16
16 files changed, 316 insertions, 203 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 33f222c2e5..1cddb6fd29 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -265,11 +265,6 @@ private:
/// Mapping from __block VarDecls to BlockVarCopyInit.
llvm::DenseMap<const VarDecl *, BlockVarCopyInit> BlockVarCopyInits;
- /// Mapping from class scope functions specialization to their
- /// template patterns.
- llvm::DenseMap<const FunctionDecl*, FunctionDecl*>
- ClassScopeSpecializationPattern;
-
/// Mapping from materialized temporaries with static storage duration
/// that appear in constant initializers to their evaluated values. These are
/// allocated in a std::map because their address must be stable.
@@ -891,11 +886,6 @@ public:
TemplateOrSpecializationInfo
getTemplateOrSpecializationInfo(const VarDecl *Var);
- FunctionDecl *getClassScopeSpecializationPattern(const FunctionDecl *FD);
-
- void setClassScopeSpecializationPattern(FunctionDecl *FD,
- FunctionDecl *Pattern);
-
/// Note that the static data member \p Inst is an instantiation of
/// the static data member template \p Tmpl of a class template.
void setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl,
diff --git a/include/clang/AST/ASTNodeTraverser.h b/include/clang/AST/ASTNodeTraverser.h
index 6268df8036..220c763d6e 100644
--- a/include/clang/AST/ASTNodeTraverser.h
+++ b/include/clang/AST/ASTNodeTraverser.h
@@ -221,8 +221,12 @@ public:
Visit(TP);
}
- void dumpTemplateArgumentListInfo(const TemplateArgumentListInfo &TALI) {
- for (const auto &TA : TALI.arguments())
+ void
+ dumpASTTemplateArgumentListInfo(const ASTTemplateArgumentListInfo *TALI) {
+ if (!TALI)
+ return;
+
+ for (const auto &TA : TALI->arguments())
dumpTemplateArgumentLoc(TA);
}
@@ -465,8 +469,7 @@ public:
void VisitClassScopeFunctionSpecializationDecl(
const ClassScopeFunctionSpecializationDecl *D) {
Visit(D->getSpecialization());
- if (D->hasExplicitTemplateArgs())
- dumpTemplateArgumentListInfo(D->templateArgs());
+ dumpASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten());
}
void VisitVarTemplateDecl(const VarTemplateDecl *D) { dumpTemplateDecl(D); }
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index dc7d5657e9..507ca73fcb 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -1742,10 +1742,19 @@ class FunctionDecl : public DeclaratorDecl,
public:
/// The kind of templated function a FunctionDecl can be.
enum TemplatedKind {
+ // Not templated.
TK_NonTemplate,
+ // The pattern in a function template declaration.
TK_FunctionTemplate,
+ // A non-template function that is an instantiation or explicit
+ // specialization of a member of a templated class.
TK_MemberSpecialization,
+ // An instantiation or explicit specialization of a function template.
+ // Note: this might have been instantiated from a templated class if it
+ // is a class-scope explicit specialization.
TK_FunctionTemplateSpecialization,
+ // A function template specialization that hasn't yet been resolved to a
+ // particular specialized function template.
TK_DependentFunctionTemplateSpecialization
};
@@ -2440,10 +2449,6 @@ public:
return getPrimaryTemplate() != nullptr;
}
- /// Retrieve the class scope template pattern that this function
- /// template specialization is instantiated from.
- FunctionDecl *getClassScopeSpecializationPattern() const;
-
/// If this function is actually a function template specialization,
/// retrieve information about this function template specialization.
/// Otherwise, returns NULL.
@@ -2530,6 +2535,11 @@ public:
/// represents.
TemplateSpecializationKind getTemplateSpecializationKind() const;
+ /// Determine the kind of template specialization this function represents
+ /// for the purpose of template instantiation.
+ TemplateSpecializationKind
+ getTemplateSpecializationKindForInstantiation() const;
+
/// Determine what kind of template instantiation this function
/// represents.
void setTemplateSpecializationKind(TemplateSpecializationKind TSK,
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index 3ac3f37469..a6d9e3904e 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -504,29 +504,13 @@ public:
/// Provides information about a function template specialization,
/// which is a FunctionDecl that has been explicitly specialization or
/// instantiated from a function template.
-class FunctionTemplateSpecializationInfo : public llvm::FoldingSetNode {
- FunctionTemplateSpecializationInfo(FunctionDecl *FD,
- FunctionTemplateDecl *Template,
- TemplateSpecializationKind TSK,
- const TemplateArgumentList *TemplateArgs,
- const ASTTemplateArgumentListInfo *TemplateArgsAsWritten,
- SourceLocation POI)
- : Function(FD), Template(Template, TSK - 1),
- TemplateArguments(TemplateArgs),
- TemplateArgumentsAsWritten(TemplateArgsAsWritten),
- PointOfInstantiation(POI) {}
-
-public:
- static FunctionTemplateSpecializationInfo *
- Create(ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template,
- TemplateSpecializationKind TSK,
- const TemplateArgumentList *TemplateArgs,
- const TemplateArgumentListInfo *TemplateArgsAsWritten,
- SourceLocation POI);
-
- /// The function template specialization that this structure
- /// describes.
- FunctionDecl *Function;
+class FunctionTemplateSpecializationInfo final
+ : public llvm::FoldingSetNode,
+ private llvm::TrailingObjects<FunctionTemplateSpecializationInfo,
+ MemberSpecializationInfo *> {
+ /// The function template specialization that this structure describes and a
+ /// flag indicating if the function is a member specialization.
+ llvm::PointerIntPair<FunctionDecl *, 1, bool> Function;
/// The function template from which this function template
/// specialization was generated.
@@ -534,17 +518,50 @@ public:
/// The two bits contain the top 4 values of TemplateSpecializationKind.
llvm::PointerIntPair<FunctionTemplateDecl *, 2> Template;
+public:
/// The template arguments used to produce the function template
/// specialization from the function template.
const TemplateArgumentList *TemplateArguments;
/// The template arguments as written in the sources, if provided.
+ /// FIXME: Normally null; tail-allocate this.
const ASTTemplateArgumentListInfo *TemplateArgumentsAsWritten;
/// The point at which this function template specialization was
/// first instantiated.
SourceLocation PointOfInstantiation;
+private:
+ FunctionTemplateSpecializationInfo(
+ FunctionDecl *FD, FunctionTemplateDecl *Template,
+ TemplateSpecializationKind TSK, const TemplateArgumentList *TemplateArgs,
+ const ASTTemplateArgumentListInfo *TemplateArgsAsWritten,
+ SourceLocation POI, MemberSpecializationInfo *MSInfo)
+ : Function(FD, MSInfo ? 1 : 0), Template(Template, TSK - 1),
+ TemplateArguments(TemplateArgs),
+ TemplateArgumentsAsWritten(TemplateArgsAsWritten),
+ PointOfInstantiation(POI) {
+ if (MSInfo)
+ getTrailingObjects<MemberSpecializationInfo *>()[0] = MSInfo;
+ }
+
+ size_t numTrailingObjects(OverloadToken<MemberSpecializationInfo*>) const {
+ return Function.getInt();
+ }
+
+public:
+ friend TrailingObjects;
+
+ static FunctionTemplateSpecializationInfo *
+ Create(ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template,
+ TemplateSpecializationKind TSK,
+ const TemplateArgumentList *TemplateArgs,
+ const TemplateArgumentListInfo *TemplateArgsAsWritten,
+ SourceLocation POI, MemberSpecializationInfo *MSInfo);
+
+ /// Retrieve the declaration of the function template specialization.
+ FunctionDecl *getFunction() const { return Function.getPointer(); }
+
/// Retrieve the template from which this function was specialized.
FunctionTemplateDecl *getTemplate() const { return Template.getPointer(); }
@@ -587,9 +604,44 @@ public:
PointOfInstantiation = POI;
}
+ /// Get the specialization info if this function template specialization is
+ /// also a member specialization:
+ ///
+ /// \code
+ /// template<typename> struct A {
+ /// template<typename> void f();
+ /// template<> void f<int>(); // ClassScopeFunctionSpecializationDecl
+ /// };
+ /// \endcode
+ ///
+ /// Here, A<int>::f<int> is a function template specialization that is
+ /// an explicit specialization of A<int>::f, but it's also a member
+ /// specialization (an implicit instantiation in this case) of A::f<int>.
+ /// Further:
+ ///
+ /// \code
+ /// template<> template<> void A<int>::f<int>() {}
+ /// \endcode
+ ///
+ /// ... declares a function template specialization that is an explicit
+ /// specialization of A<int>::f, and is also an explicit member
+ /// specialization of A::f<int>.
+ ///
+ /// Note that the TemplateSpecializationKind of the MemberSpecializationInfo
+ /// need not be the same as that returned by getTemplateSpecializationKind(),
+ /// and represents the relationship between the function and the class-scope
+ /// explicit specialization in the original templated class -- whereas our
+ /// TemplateSpecializationKind represents the relationship between the
+ /// function and the function template, and should always be
+ /// TSK_ExplicitSpecialization whenever we have MemberSpecializationInfo.
+ MemberSpecializationInfo *getMemberSpecializationInfo() const {
+ return numTrailingObjects(OverloadToken<MemberSpecializationInfo *>())
+ ? getTrailingObjects<MemberSpecializationInfo *>()[0]
+ : nullptr;
+ }
+
void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, TemplateArguments->asArray(),
- Function->getASTContext());
+ Profile(ID, TemplateArguments->asArray(), getFunction()->getASTContext());
}
static void
@@ -955,7 +1007,7 @@ SpecEntryTraits<FunctionTemplateSpecializationInfo> {
using DeclType = FunctionDecl;
static DeclType *getDecl(FunctionTemplateSpecializationInfo *I) {
- return I->Function;
+ return I->getFunction();
}
static ArrayRef<TemplateArgument>
@@ -2408,8 +2460,6 @@ public:
/// Declaration of a function specialization at template class scope.
///
-/// This is a non-standard extension needed to support MSVC.
-///
/// For example:
/// \code
/// template <class T>
@@ -2422,17 +2472,18 @@ public:
/// "template<> foo(int a)" will be saved in Specialization as a normal
/// CXXMethodDecl. Then during an instantiation of class A, it will be
/// transformed into an actual function specialization.
+///
+/// FIXME: This is redundant; we could store the same information directly on
+/// the CXXMethodDecl as a DependentFunctionTemplateSpecializationInfo.
class ClassScopeFunctionSpecializationDecl : public Decl {
CXXMethodDecl *Specialization;
- bool HasExplicitTemplateArgs;
- TemplateArgumentListInfo TemplateArgs;
+ const ASTTemplateArgumentListInfo *TemplateArgs;
- ClassScopeFunctionSpecializationDecl(DeclContext *DC, SourceLocation Loc,
- CXXMethodDecl *FD, bool Args,
- TemplateArgumentListInfo TemplArgs)
+ ClassScopeFunctionSpecializationDecl(
+ DeclContext *DC, SourceLocation Loc, CXXMethodDecl *FD,
+ const ASTTemplateArgumentListInfo *TemplArgs)
: Decl(Decl::ClassScopeFunctionSpecialization, DC, Loc),
- Specialization(FD), HasExplicitTemplateArgs(Args),
- TemplateArgs(std::move(TemplArgs)) {}
+ Specialization(FD), TemplateArgs(TemplArgs) {}
ClassScopeFunctionSpecializationDecl(EmptyShell Empty)
: Decl(Decl::ClassScopeFunctionSpecialization, Empty) {}
@@ -2444,17 +2495,20 @@ public:
friend class ASTDeclWriter;
CXXMethodDecl *getSpecialization() const { return Specialization; }
- bool hasExplicitTemplateArgs() const { return HasExplicitTemplateArgs; }
- const TemplateArgumentListInfo& templateArgs() const { return TemplateArgs; }
-
- static ClassScopeFunctionSpecializationDecl *Create(ASTContext &C,
- DeclContext *DC,
- SourceLocation Loc,
- CXXMethodDecl *FD,
- bool HasExplicitTemplateArgs,
- TemplateArgumentListInfo TemplateArgs) {
+ bool hasExplicitTemplateArgs() const { return TemplateArgs; }
+ const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
+ return TemplateArgs;
+ }
+
+ static ClassScopeFunctionSpecializationDecl *
+ Create(ASTContext &C, DeclContext *DC, SourceLocation Loc, CXXMethodDecl *FD,
+ bool HasExplicitTemplateArgs,
+ const TemplateArgumentListInfo &TemplateArgs) {
return new (C, DC) ClassScopeFunctionSpecializationDecl(
- DC, Loc, FD, HasExplicitTemplateArgs, std::move(TemplateArgs));
+ DC, Loc, FD,
+ HasExplicitTemplateArgs
+ ? ASTTemplateArgumentListInfo::Create(C, TemplateArgs)
+ : nullptr);
}
static ClassScopeFunctionSpecializationDecl *
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 719f2bc4b9..22ef332dbb 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -1458,9 +1458,9 @@ DEF_TRAVERSE_DECL(ClassScopeFunctionSpecializationDecl, {
TRY_TO(TraverseDecl(D->getSpecialization()));
if (D->hasExplicitTemplateArgs()) {
- const TemplateArgumentListInfo &args = D->templateArgs();
- TRY_TO(TraverseTemplateArgumentLocsHelper(args.getArgumentArray(),
- args.size()));
+ TRY_TO(TraverseTemplateArgumentLocsHelper(
+ D->getTemplateArgsAsWritten()->getTemplateArgs(),
+ D->getTemplateArgsAsWritten()->NumTemplateArgs));
}
})
diff --git a/include/clang/Sema/Template.h b/include/clang/Sema/Template.h
index b2f0fbb9ba..61de93449e 100644
--- a/include/clang/Sema/Template.h
+++ b/include/clang/Sema/Template.h
@@ -475,7 +475,8 @@ class VarDecl;
// A few supplemental visitor functions.
Decl *VisitCXXMethodDecl(CXXMethodDecl *D,
TemplateParameterList *TemplateParams,
- bool IsClassScopeSpecialization = false);
+ Optional<const ASTTemplateArgumentListInfo *>
+ ClassScopeSpecializationArgs = llvm::None);
Decl *VisitFunctionDecl(FunctionDecl *D,
TemplateParameterList *TemplateParams);
Decl *VisitDecl(Decl *D);
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index ad76e529bd..d0a790cad4 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1381,24 +1381,6 @@ ASTContext::setTemplateOrSpecializationInfo(VarDecl *Inst,
TemplateOrInstantiation[Inst] = TSI;
}
-FunctionDecl *ASTContext::getClassScopeSpecializationPattern(
- const FunctionDecl *FD){
- assert(FD && "Specialization is 0");
- llvm::DenseMap<const FunctionDecl*, FunctionDecl *>::const_iterator Pos
- = ClassScopeSpecializationPattern.find(FD);
- if (Pos == ClassScopeSpecializationPattern.end())
- return nullptr;
-
- return Pos->second;
-}
-
-void ASTContext::setClassScopeSpecializationPattern(FunctionDecl *FD,
- FunctionDecl *Pattern) {
- assert(FD && "Specialization is 0");
- assert(Pattern && "Class scope specialization pattern is 0");
- ClassScopeSpecializationPattern[FD] = Pattern;
-}
-
NamedDecl *
ASTContext::getInstantiatedFromUsingDecl(NamedDecl *UUD) {
auto Pos = InstantiatedFromUsingDecl.find(UUD);
@@ -10033,8 +10015,7 @@ size_t ASTContext::getSideTableAllocatedMemory() const {
llvm::capacity_in_bytes(InstantiatedFromUnnamedFieldDecl) +
llvm::capacity_in_bytes(OverriddenMethods) +
llvm::capacity_in_bytes(Types) +
- llvm::capacity_in_bytes(VariableArrayTypes) +
- llvm::capacity_in_bytes(ClassScopeSpecializationPattern);
+ llvm::capacity_in_bytes(VariableArrayTypes);
}
/// getIntTypeForBitwidth -
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 6401066629..2c1dbbd747 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -3375,7 +3375,13 @@ FunctionDecl *FunctionDecl::getInstantiatedFromMemberFunction() const {
}
MemberSpecializationInfo *FunctionDecl::getMemberSpecializationInfo() const {
- return TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo *>();
+ if (auto *MSI =
+ TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo *>())
+ return MSI;
+ if (auto *FTSI = TemplateOrSpecialization
+ .dyn_cast<FunctionTemplateSpecializationInfo *>())
+ return FTSI->getMemberSpecializationInfo();
+ return nullptr;
}
void
@@ -3394,6 +3400,8 @@ FunctionTemplateDecl *FunctionDecl::getDescribedFunctionTemplate() const {
}
void FunctionDecl::setDescribedFunctionTemplate(FunctionTemplateDecl *Template) {
+ assert(TemplateOrSpecialization.isNull() &&
+ "Member function is already a specialization");
TemplateOrSpecialization = Template;
}
@@ -3402,19 +3410,15 @@ bool FunctionDecl::isImplicitlyInstantiable() const {
if (isInvalidDecl())
return false;
- switch (getTemplateSpecializationKind()) {
+ switch (getTemplateSpecializationKindForInstantiation()) {
case TSK_Undeclared:
case TSK_ExplicitInstantiationDefinition:
+ case TSK_ExplicitSpecialization:
return false;
case TSK_ImplicitInstantiation:
return true;
- // It is possible to instantiate TSK_ExplicitSpecialization kind
- // if the FunctionDecl has a class scope specialization pattern.
- case TSK_ExplicitSpecialization:
- return getClassScopeSpecializationPattern() != nullptr;
-
case TSK_ExplicitInstantiationDeclaration:
// Handled below.
break;
@@ -3437,26 +3441,12 @@ bool FunctionDecl::isImplicitlyInstantiable() const {
}
bool FunctionDecl::isTemplateInstantiation() const {
- switch (getTemplateSpecializationKind()) {
- case TSK_Undeclared:
- case TSK_ExplicitSpecialization:
- return false;
- case TSK_ImplicitInstantiation:
- case TSK_ExplicitInstantiationDeclaration:
- case TSK_ExplicitInstantiationDefinition:
- return true;
- }
- llvm_unreachable("All TSK values handled.");
+ // FIXME: Remove this, it's not clear what it means. (Which template
+ // specialization kind?)
+ return clang::isTemplateInstantiation(getTemplateSpecializationKind());
}
FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const {
- // Handle class scope explicit specialization special case.
- if (getTemplateSpecializationKind() == TSK_ExplicitSpecialization) {
- if (auto *Spec = getClassScopeSpecializationPattern())
- return getDefinitionOrSelf(Spec);
- return nullptr;
- }
-
// If this is a generic lambda call operator specialization, its
// instantiation pattern is always its primary template's pattern
// even if its primary template was instantiated from another
@@ -3472,6 +3462,15 @@ FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const {
return getDefinitionOrSelf(getPrimaryTemplate()->getTemplatedDecl());
}
+ if (MemberSpecializationInfo *Info = getMemberSpecializationInfo()) {
+ if (!clang::isTemplateInstantiation(Info->getTemplateSpecializationKind()))
+ return nullptr;
+ return getDefinitionOrSelf(cast<FunctionDecl>(Info->getInstantiatedFrom()));
+ }
+
+ if (!clang::isTemplateInstantiation(getTemplateSpecializationKind()))
+ return nullptr;
+
if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) {
while (Primary->getInstantiatedFromMemberTemplate()) {
// If we have hit a point where the user provided a specialization of
@@ -3484,9 +3483,6 @@ FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const {
return getDefinitionOrSelf(Primary->getTemplatedDecl());
}
- if (auto *MFD = getInstantiatedFromMemberFunction())
- return getDefinitionOrSelf(MFD);
-
return nullptr;
}
@@ -3494,15 +3490,11 @@ FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const {
if (FunctionTemplateSpecializationInfo *Info
= TemplateOrSpecialization
.dyn_cast<FunctionTemplateSpecializationInfo*>()) {
- return Info->Template.getPointer();
+ return Info->getTemplate();
}
return nullptr;
}
-FunctionDecl *FunctionDecl::getClassScopeSpecializationPattern() const {
- return getASTContext().getClassScopeSpecializationPattern(this);
-}
-
FunctionTemplateSpecializationInfo *
FunctionDecl::getTemplateSpecializationInfo() const {
return TemplateOrSpecialization
@@ -3537,15 +3529,19 @@ FunctionDecl::setFunctionTemplateSpecialization(ASTContext &C,
TemplateSpecializationKind TSK,
const TemplateArgumentListInfo *TemplateArgsAsWritten,
SourceLocation PointOfInstantiation) {
+ assert((TemplateOrSpecialization.isNull() ||
+ TemplateOrSpecialization.is<MemberSpecializationInfo *>()) &&
+ "Member function is already a specialization");
assert(TSK != TSK_Undeclared &&
"Must specify the type of function template specialization");
- FunctionTemplateSpecializationInfo *Info
- = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
- if (!Info)
- Info = FunctionTemplateSpecializationInfo::Create(C, this, Template, TSK,
- TemplateArgs,
- TemplateArgsAsWritten,
- PointOfInstantiation);
+ assert((TemplateOrSpecialization.isNull() ||
+ TSK == TSK_ExplicitSpecialization) &&
+ "Member specialization must be an explicit specialization");
+ FunctionTemplateSpecializationInfo *Info =
+ FunctionTemplateSpecializationInfo::Create(
+ C, this, Template, TSK, TemplateArgs, TemplateArgsAsWritten,
+ PointOfInstantiation,
+ TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo *>());
TemplateOrSpecialization = Info;
Template->addSpecialization(Info, InsertPos);
}
@@ -3596,14 +3592,47 @@ DependentFunctionTemplateSpecializationInfo(const UnresolvedSetImpl &Ts,
TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const {
// For a function template specialization, query the specialization
// information object.
- FunctionTemplateSpecializationInfo *FTSInfo
- = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
- if (FTSInfo)
+ if (FunctionTemplateSpecializationInfo *FTSInfo =
+ TemplateOrSpecialization
+ .dyn_cast<FunctionTemplateSpecializationInfo *>())
+ return FTSInfo->getTemplateSpecializationKind();
+
+ if (MemberSpecializationInfo *MSInfo =
+ TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo *>())
+ return MSInfo->getTemplateSpecializationKind();
+
+ return TSK_Undeclared;
+}
+
+TemplateSpecializationKind
+FunctionDecl::getTemplateSpecializationKindForInstantiation() const {
+ // This is the same as getTemplateSpecializationKind(), except that for a
+ // function that is both a function template specialization and a member
+ // specialization, we prefer the member specialization information. Eg:
+ //
+ // template<typename T> struct A {
+ // template<typename U> void f() {}
+ // template<> void f<int>() {}
+ // };
+ //
+ // For A<int>::f<int>():
+ // * getTemplateSpecializationKind() will return TSK_ExplicitSpecialization
+ // * getTemplateSpecializationKindForInstantiation() will return
+ // TSK_ImplicitInstantiation
+ //
+ // This reflects the facts that A<int>::f<int> is an explicit specialization
+ // of A<int>::f, and that A<int>::f<int> should be implicitly instantiated
+ // from A::f<int> if a definition is needed.
+ if (FunctionTemplateSpecializationInfo *FTSInfo =
+ TemplateOrSpecialization
+ .dyn_cast<FunctionTemplateSpecializationInfo *>()) {
+ if (auto *MSInfo = FTSInfo->getMemberSpecializationInfo())
+ return MSInfo->getTemplateSpecializationKind();
return FTSInfo->getTemplateSpecializationKind();
+ }
- MemberSpecializationInfo *MSInfo
- = TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>();
- if (MSInfo)
+ if (MemberSpecializationInfo *MSInfo =
+ TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo *>())
return MSInfo->getTemplateSpecializationKind();
return TSK_Undeclared;
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index 592258d3ff..3c4cf72f7f 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -687,22 +687,20 @@ TemplateArgumentList::CreateCopy(ASTContext &Context,
return new (Mem) TemplateArgumentList(Args);
}
-FunctionTemplateSpecializationInfo *
-FunctionTemplateSpecializationInfo::Create(ASTContext &C, FunctionDecl *FD,
- FunctionTemplateDecl *Template,
- TemplateSpecializationKind TSK,
- const TemplateArgumentList *TemplateArgs,
- const TemplateArgumentListInfo *TemplateArgsAsWritten,
- SourceLocation POI) {
+FunctionTemplateSpecializationInfo *FunctionTemplateSpecializationInfo::Create(
+ ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template,
+ TemplateSpecializationKind TSK, const TemplateArgumentList *TemplateArgs,
+ const TemplateArgumentListInfo *TemplateArgsAsWritten, SourceLocation POI,
+ MemberSpecializationInfo *MSInfo) {
const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr;
if (TemplateArgsAsWritten)
ArgsAsWritten = ASTTemplateArgumentListInfo::Create(C,
*TemplateArgsAsWritten);
- return new (C) FunctionTemplateSpecializationInfo(FD, Template, TSK,
- TemplateArgs,
- ArgsAsWritten,
- POI);
+ void *Mem =
+ C.Allocate(totalSizeToAlloc<MemberSpecializationInfo *>(MSInfo ? 1 : 0));
+ return new (Mem) FunctionTemplateSpecializationInfo(
+ FD, Template, TSK, TemplateArgs, ArgsAsWritten, POI, MSInfo);
}
//===----------------------------------------------------------------------===//
@@ -935,7 +933,7 @@ ClassScopeFunctionSpecializationDecl *
ClassScopeFunctionSpecializationDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
return new (C, ID) ClassScopeFunctionSpecializationDecl(
- nullptr, SourceLocation(), nullptr, false, TemplateArgumentListInfo());
+ nullptr, SourceLocation(), nullptr, nullptr);
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index e64eeecb2a..9564c8f0cb 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -14859,7 +14859,8 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
// Implicit instantiation of function templates and member functions of
// class templates.
if (Func->isImplicitlyInstantiable()) {
- TemplateSpecializationKind TSK = Func->getTemplateSpecializationKind();
+ TemplateSpecializationKind TSK =
+ Func->getTemplateSpecializationKindForInstantiation();
SourceLocation PointOfInstantiation = Func->getPointOfInstantiation();
bool FirstInstantiation = PointOfInstantiation.isInvalid();
if (FirstInstantiation) {
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 03822e2c78..af56ff06ac 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -133,9 +133,8 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
// Add template arguments from a function template specialization.
else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Ctx)) {
if (!RelativeToPrimary &&
- (Function->getTemplateSpecializationKind() ==
- TSK_ExplicitSpecialization &&
- !Function->getClassScopeSpecializationPattern()))
+ Function->getTemplateSpecializationKindForInstantiation() ==
+ TSK_ExplicitSpecialization)
break;
if (const TemplateArgumentList *TemplateArgs
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 531defdf23..90ae8989c1 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1951,10 +1951,10 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
return Function;
}
-Decl *
-TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
- TemplateParameterList *TemplateParams,
- bool IsClassScopeSpecialization) {
+Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
+ CXXMethodDecl *D, TemplateParameterList *TemplateParams,
+ Optional<const ASTTemplateArgumentListInfo *>
+ ClassScopeSpecializationArgs) {
FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
if (FunctionTemplate && !TemplateParams) {
// We are creating a function template specialization from a function
@@ -2158,7 +2158,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
IsExplicitSpecialization = true;
} else if (const ASTTemplateArgumentListInfo *Info =
- D->getTemplateSpecializationArgsAsWritten()) {
+ ClassScopeSpecializationArgs.getValueOr(
+ D->getTemplateSpecializationArgsAsWritten())) {
SemaRef.LookupQualifiedName(Previous, DC);
TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(),
@@ -2173,6 +2174,14 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
Method->setInvalidDecl();
IsExplicitSpecialization = true;
+ } else if (ClassScopeSpecializationArgs) {
+ // Class-scope explicit specialization written without explicit template
+ // arguments.
+ SemaRef.LookupQualifiedName(Previous, DC);
+ if (SemaRef.CheckFunctionTemplateSpecialization(Method, nullptr, Previous))
+ Method->setInvalidDecl();
+
+ IsExplicitSpecialization = true;
} else if (!FunctionTemplate || TemplateParams || isFriend) {
SemaRef.LookupQualifiedName(Previous, Record);
@@ -2184,9 +2193,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
Previous.clear();
}
- if (!IsClassScopeSpecialization)
- SemaRef.CheckFunctionDeclaration(nullptr, Method, Previous,
- IsExplicitSpecialization);
+ SemaRef.CheckFunctionDeclaration(nullptr, Method, Previous,
+ IsExplicitSpecialization);
if (D->isPure())
SemaRef.CheckPureMethod(Method, SourceRange());
@@ -2209,6 +2217,12 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
if (D->isDeletedAsWritten())
SemaRef.SetDeclDeleted(Method, Method->getLocation());
+ // If this is an explicit specialization, mark the implicitly-instantiated
+ // template specialization as being an explicit specialization too.
+ // FIXME: Is this necessary?
+ if (IsExplicitSpecialization && !isFriend)
+ SemaRef.CompleteMemberSpecialization(Method, Previous);
+
// If there's a function template, let our caller handle it.
if (FunctionTemplate) {
// do nothing
@@ -2229,7 +2243,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
// Otherwise, add the declaration. We don't need to do this for
// class-scope specializations because we'll have matched them with
// the appropriate template.
- } else if (!IsClassScopeSpecialization) {
+ } else {
Owner->addDecl(Method);
}
@@ -2839,38 +2853,8 @@ Decl *TemplateDeclInstantiator::VisitUsingPackDecl(UsingPackDecl *D) {
Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl(
ClassScopeFunctionSpecializationDecl *Decl) {
CXXMethodDecl *OldFD = Decl->getSpecialization();
- CXXMethodDecl *NewFD =
- cast_or_null<CXXMethodDecl>(VisitCXXMethodDecl(OldFD, nullptr, true));
- if (!NewFD)
- return nullptr;
-
- TemplateArgumentListInfo ExplicitTemplateArgs;
- TemplateArgumentListInfo *ExplicitTemplateArgsPtr = nullptr;
- if (Decl->hasExplicitTemplateArgs()) {
- if (SemaRef.Subst(Decl->templateArgs().getArgumentArray(),
- Decl->templateArgs().size(), ExplicitTemplateArgs,
- TemplateArgs))
- return nullptr;
- ExplicitTemplateArgsPtr = &ExplicitTemplateArgs;
- }
-
- LookupResult Previous(SemaRef, NewFD->getNameInfo(), Sema::LookupOrdinaryName,
- Sema::ForExternalRedeclaration);
- SemaRef.LookupQualifiedName(Previous, SemaRef.CurContext);
- if (SemaRef.CheckFunctionTemplateSpecialization(
- NewFD, ExplicitTemplateArgsPtr, Previous)) {
- NewFD->setInvalidDecl();
- return NewFD;
- }
-
- // Associate the specialization with the pattern.
- FunctionDecl *Specialization = cast<FunctionDecl>(Previous.getFoundDecl());
- assert(Specialization && "Class scope Specialization is null");
- SemaRef.Context.setClassScopeSpecializationPattern(Specialization, OldFD);
-
- // FIXME: If this is a definition, check for redefinition errors!
-
- return NewFD;
+ return cast_or_null<CXXMethodDecl>(
+ VisitCXXMethodDecl(OldFD, nullptr, Decl->getTemplateArgsAsWritten()));
}
Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl(
@@ -4068,9 +4052,9 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
// Never instantiate an explicit specialization except if it is a class scope
// explicit specialization.
- TemplateSpecializationKind TSK = Function->getTemplateSpecializationKind();
- if (TSK == TSK_ExplicitSpecialization &&
- !Function->getClassScopeSpecializationPattern())
+ TemplateSpecializationKind TSK =
+ Function->getTemplateSpecializationKindForInstantiation();
+ if (TSK == TSK_ExplicitSpecialization)
return;
// Find the function body that we'll be substituting.
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 32bd82d077..ffe0e8bd74 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -928,12 +928,22 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
TemplateArgumentListInfo TemplArgsInfo(LAngleLoc, RAngleLoc);
for (unsigned i = 0, e = TemplArgLocs.size(); i != e; ++i)
TemplArgsInfo.addArgument(TemplArgLocs[i]);
- FunctionTemplateSpecializationInfo *FTInfo
- = FunctionTemplateSpecializationInfo::Create(C, FD, Template, TSK,
- TemplArgList,
- HasTemplateArgumentsAsWritten ? &TemplArgsInfo
- : nullptr,
- POI);
+
+ MemberSpecializationInfo *MSInfo = nullptr;
+ if (Record.readInt()) {
+ auto *FD = ReadDeclAs<FunctionDecl>();
+ auto TSK = (TemplateSpecializationKind)Record.readInt();
+ SourceLocation POI = ReadSourceLocation();
+
+ MSInfo = new (C) MemberSpecializationInfo(FD, TSK);
+ MSInfo->setPointOfInstantiation(POI);
+ }
+
+ FunctionTemplateSpecializationInfo *FTInfo =
+ FunctionTemplateSpecializationInfo::Create(
+ C, FD, Template, TSK, TemplArgList,
+ HasTemplateArgumentsAsWritten ? &TemplArgsInfo : nullptr, POI,
+ MSInfo);
FD->TemplateOrSpecialization = FTInfo;
if (FD->isCanonicalDecl()) { // if canonical add to template's set.
@@ -956,7 +966,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
else {
assert(Reader.getContext().getLangOpts().Modules &&
"already deserialized this template specialization");
- mergeRedeclarable(FD, ExistingInfo->Function, Redecl);
+ mergeRedeclarable(FD, ExistingInfo->getFunction(), Redecl);
}
}
break;
@@ -2244,6 +2254,8 @@ void ASTDeclReader::VisitClassScopeFunctionSpecializationDecl(
ClassScopeFunctionSpecializationDecl *D) {
VisitDecl(D);
D->Specialization = ReadDeclAs<CXXMethodDecl>();
+ if (Record.readInt())
+ D->TemplateArgs = Record.readASTTemplateArgumentListInfo();
}
void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index c08abb805f..159a76d5ef 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -596,6 +596,16 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
Record.AddSourceLocation(FTSInfo->getPointOfInstantiation());
+ if (MemberSpecializationInfo *MemberInfo =
+ FTSInfo->getMemberSpecializationInfo()) {
+ Record.push_back(1);
+ Record.AddDeclRef(MemberInfo->getInstantiatedFrom());
+ Record.push_back(MemberInfo->getTemplateSpecializationKind());
+ Record.AddSourceLocation(MemberInfo->getPointOfInstantiation());
+ } else {
+ Record.push_back(0);
+ }
+
if (D->isCanonicalDecl()) {
// Write the template that contains the specializations set. We will
// add a FunctionTemplateSpecializationInfo to it when reading.
@@ -1555,6 +1565,9 @@ void ASTDeclWriter::VisitClassScopeFunctionSpecializationDecl(
ClassScopeFunctionSpecializationDecl *D) {
VisitDecl(D);
Record.AddDeclRef(D->getSpecialization());
+ Record.push_back(D->hasExplicitTemplateArgs());
+ if (D->hasExplicitTemplateArgs())
+ Record.AddASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten());
Code = serialization::DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION;
}
diff --git a/test/PCH/cxx-templates.cpp b/test/PCH/cxx-templates.cpp
index a7f7b1981f..f41646dd5e 100644
--- a/test/PCH/cxx-templates.cpp
+++ b/test/PCH/cxx-templates.cpp
@@ -1,20 +1,20 @@
// Test this without pch.
-// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include %S/cxx-templates.h -verify %s -ast-dump -o -
+// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include %S/cxx-templates.h -verify %s
// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include %S/cxx-templates.h %s -emit-llvm -o - -DNO_ERRORS | FileCheck %s
// Test with pch.
// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -x c++-header -emit-pch -o %t %S/cxx-templates.h
-// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include-pch %t -verify %s -ast-dump -o -
+// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include-pch %t -verify %s
// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include-pch %t %s -emit-llvm -o - -error-on-deserialized-decl doNotDeserialize -DNO_ERRORS | FileCheck %s
// Test with modules.
// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fmodules -x c++-header -emit-pch -o %t %S/cxx-templates.h
-// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fmodules -include-pch %t -verify %s -ast-dump -o -
+// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fmodules -include-pch %t -verify %s
// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fmodules -include-pch %t %s -emit-llvm -o - -error-on-deserialized-decl doNotDeserialize -DNO_ERRORS -fmodules-ignore-macro=NO_ERRORS | FileCheck %s
// Test with pch and delayed template parsing.
// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fdelayed-template-parsing -fexceptions -x c++-header -emit-pch -o %t %S/cxx-templates.h
-// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fdelayed-template-parsing -fexceptions -include-pch %t -verify %s -ast-dump -o -
+// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fdelayed-template-parsing -fexceptions -include-pch %t -verify %s
// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fdelayed-template-parsing -fexceptions -include-pch %t %s -emit-llvm -o - -DNO_ERRORS | FileCheck %s
// CHECK: define weak_odr {{.*}}void @_ZN2S4IiE1mEv
@@ -132,3 +132,25 @@ int test() {
return z1 + z2 + z3;
}
} // end namespace PR34728
+
+namespace ClassScopeExplicitSpecializations {
+ // FIXME: It's unclear these warnings (and the behavior they're describing)
+ // are desirable. These explicit instantiations could meaningfully
+ // instantiate the explicit specializations defined in the primary template.
+ template int A<3>::f<0>() const; // expected-warning {{has no effect}}
+ template int A<3>::f<1>() const;
+ template int A<4>::f<0>() const; // expected-warning {{has no effect}}
+ template int A<4>::f<1>() const;
+ // expected-note@cxx-templates.h:403 2{{here}}
+
+ static_assert(A<0>().f<1>() == 3, "");
+ static_assert(A<0>().f<0>() == 4, "");
+ static_assert(A<1>().f<1>() == 1, "");
+ static_assert(A<1>().f<0>() == 2, "");
+ static_assert(A<2>().f<1>() == 1, "");
+ static_assert(A<2>().f<0>() == 2, "");
+ static_assert(A<3>().f<1>() == 1, "");
+ static_assert(A<3>().f<0>() == 2, "");
+ static_assert(A<4>().f<1>() == 1, "");
+ static_assert(A<4>().f<0>() == 2, "");
+}
diff --git a/test/PCH/cxx-templates.h b/test/PCH/cxx-templates.h
index e812aa68fb..f2111428ac 100644
--- a/test/PCH/cxx-templates.h
+++ b/test/PCH/cxx-templates.h
@@ -396,3 +396,19 @@ C<D> func3(D const &d) {
}
} // end namespace PR34728
+
+namespace ClassScopeExplicitSpecializations {
+ template<int> struct A {
+ template<int> constexpr int f() const { return 1; }
+ template<> constexpr int f<0>() const { return 2; }
+ };
+ template<> template<int> constexpr int A<0>::f() const { return 3; }
+ template<> template<> constexpr int A<0>::f<0>() const { return 4; }
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Winstantiation-after-specialization"
+ template int A<2>::f<0>() const;
+#pragma clang diagnostic pop
+ template int A<2>::f<1>() const;
+ extern template int A<3>::f<0>() const;
+ extern template int A<3>::f<1>() const;
+}