Improve the AST representation and semantic analysis for extern
templates. We now distinguish between an explicit instantiation
declaration and an explicit instantiation definition, and know not to
instantiate explicit instantiation declarations. Unfortunately, there
is some remaining confusion w.r.t. instantiation of out-of-line member
function definitions that causes trouble here.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@81053 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 1d6c9c1..28456ff 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -715,6 +715,29 @@
static bool classof(const OriginalParmVarDecl *D) { return true; }
};
+// \brief Describes the kind of template specialization that a
+// particular template specialization declaration represents.
+enum TemplateSpecializationKind {
+ /// This template specialization was formed from a template-id but
+ /// has not yet been declared, defined, or instantiated.
+ TSK_Undeclared = 0,
+ /// This template specialization was implicitly instantiated from a
+ /// template. (C++ [temp.inst]).
+ TSK_ImplicitInstantiation,
+ /// This template specialization was declared or defined by an
+ /// explicit specialization (C++ [temp.expl.spec]) or partial
+ /// specialization (C++ [temp.class.spec]).
+ TSK_ExplicitSpecialization,
+ /// This template specialization was instantiated from a template
+ /// due to an explicit instantiation declaration request
+ /// (C++0x [temp.explicit]).
+ TSK_ExplicitInstantiationDeclaration,
+ /// This template specialization was instantiated from a template
+ /// due to an explicit instantiation definition request
+ /// (C++ [temp.explicit]).
+ TSK_ExplicitInstantiationDefinition
+};
+
/// FunctionDecl - An instance of this class is created to represent a
/// function declaration or definition.
///
@@ -1077,14 +1100,14 @@
const TemplateArgumentList *TemplateArgs,
void *InsertPos);
- /// \brief Determine whether this is an explicit specialization of a
- /// function template or a member function of a class template.
- bool isExplicitSpecialization() const;
+ /// \brief Determine what kind of template instantiation this function
+ /// represents.
+ TemplateSpecializationKind getTemplateSpecializationKind() const;
- /// \brief Note that this is an explicit specialization of a function template
- /// or a member function of a class template.
- void setExplicitSpecialization(bool ES);
-
+ /// \brief Determine what kind of template instantiation this function
+ /// represents.
+ void setTemplateSpecializationKind(TemplateSpecializationKind TSK);
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) {
return D->getKind() >= FunctionFirst && D->getKind() <= FunctionLast;
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index 971d6ea..24524df 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -510,9 +510,8 @@
/// \brief The function template from which this function template
/// specialization was generated.
///
- /// The bit will be 0 for an implicit instantiation, 1 for an explicit
- /// specialization.
- llvm::PointerIntPair<FunctionTemplateDecl *, 1> Template;
+ /// The two bits are contain the top 4 values of TemplateSpecializationKind.
+ llvm::PointerIntPair<FunctionTemplateDecl *, 2> Template;
/// \brief The template arguments used to produce the function template
/// specialization from the function template.
@@ -520,14 +519,17 @@
/// \brief Retrieve the template from which this function was specialized.
FunctionTemplateDecl *getTemplate() const { return Template.getPointer(); }
-
- /// \brief Determine whether this is an explicit specialization.
- bool isExplicitSpecialization() const { return Template.getInt(); }
-
- /// \brief Set whether this is an explicit specialization or an implicit
- /// instantiation.
- void setExplicitSpecialization(bool ES) {
- Template.setInt(ES);
+
+ /// \brief Determine what kind of template specialization this is.
+ TemplateSpecializationKind getTemplateSpecializationKind() const {
+ return (TemplateSpecializationKind)(Template.getInt() + 1);
+ }
+
+ /// \brief Set the template specialization kind.
+ void setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
+ assert(TSK != TSK_Undeclared &&
+ "Cannot encode TSK_Undeclared for a function template specialization");
+ Template.setInt(TSK - 1);
}
void Profile(llvm::FoldingSetNodeID &ID) {
@@ -871,24 +873,6 @@
static bool classof(const TemplateTemplateParmDecl *D) { return true; }
};
-// \brief Describes the kind of template specialization that a
-// particular template specialization declaration represents.
-enum TemplateSpecializationKind {
- /// This template specialization was formed from a template-id but
- /// has not yet been declared, defined, or instantiated.
- TSK_Undeclared = 0,
- /// This template specialization was declared or defined by an
- /// explicit specialization (C++ [temp.expl.spec]) or partial
- /// specialization (C++ [temp.class.spec]).
- TSK_ExplicitSpecialization,
- /// This template specialization was implicitly instantiated from a
- /// template. (C++ [temp.inst]).
- TSK_ImplicitInstantiation,
- /// This template specialization was instantiated from a template
- /// due to an explicit instantiation request (C++ [temp.explicit]).
- TSK_ExplicitInstantiation
-};
-
/// \brief Represents a class template specialization, which refers to
/// a class template with a given set of template arguments.
///
@@ -927,7 +911,7 @@
/// \brief The kind of specialization this declaration refers to.
/// Really a value of type TemplateSpecializationKind.
- unsigned SpecializationKind : 2;
+ unsigned SpecializationKind : 3;
protected:
ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK,
@@ -972,7 +956,8 @@
ClassTemplatePartialSpecializationDecl *>
getInstantiatedFrom() const {
if (getSpecializationKind() != TSK_ImplicitInstantiation &&
- getSpecializationKind() != TSK_ExplicitInstantiation)
+ getSpecializationKind() != TSK_ExplicitInstantiationDefinition &&
+ getSpecializationKind() != TSK_ExplicitInstantiationDeclaration)
return (ClassTemplateDecl*)0;
if (SpecializedPartialSpecialization *PartialSpec
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 41ba1f1..ca1ae63 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -640,7 +640,7 @@
Info->Function = this;
Info->Template.setPointer(Template);
- Info->Template.setInt(0); // Implicit instantiation, unless told otherwise
+ Info->Template.setInt(TSK_ImplicitInstantiation - 1);
Info->TemplateArguments = TemplateArgs;
TemplateOrSpecialization = Info;
@@ -649,24 +649,35 @@
Template->getSpecializations().InsertNode(Info, InsertPos);
}
-bool FunctionDecl::isExplicitSpecialization() const {
- // FIXME: check this property for explicit specializations of member
- // functions of class templates.
- FunctionTemplateSpecializationInfo *Info
- = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
- if (!Info)
- return false;
-
- return Info->isExplicitSpecialization();
-}
-
-void FunctionDecl::setExplicitSpecialization(bool ES) {
- // FIXME: set this property for explicit specializations of member functions
- // of class templates.
+TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const {
+ // For a function template specialization, query the specialization
+ // information object.
FunctionTemplateSpecializationInfo *Info
= TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
if (Info)
- Info->setExplicitSpecialization(ES);
+ return Info->getTemplateSpecializationKind();
+
+ if (!getInstantiatedFromMemberFunction())
+ return TSK_Undeclared;
+
+ // Find the class template specialization corresponding to this instantiation
+ // of a member function.
+ const DeclContext *Parent = getDeclContext();
+ while (Parent && !isa<ClassTemplateSpecializationDecl>(Parent))
+ Parent = Parent->getParent();
+
+ if (!Parent)
+ return TSK_Undeclared;
+
+ return cast<ClassTemplateSpecializationDecl>(Parent)->getSpecializationKind();
+}
+
+void
+FunctionDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
+ FunctionTemplateSpecializationInfo *Info
+ = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
+ assert(Info && "Not a function template specialization");
+ Info->setTemplateSpecializationKind(TSK);
}
//===----------------------------------------------------------------------===//
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index cde6e89..180a686 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -250,9 +250,8 @@
// The kind of external linkage this function will have, if it is not
// inline or static.
CodeGenModule::GVALinkage External = CodeGenModule::GVA_StrongExternal;
- if (Context.getLangOptions().CPlusPlus &&
- (FD->getPrimaryTemplate() || FD->getInstantiatedFromMemberFunction()) &&
- !FD->isExplicitSpecialization())
+ if (Context.getLangOptions().CPlusPlus &&
+ FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
External = CodeGenModule::GVA_TemplateInstantiation;
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index d088387..1c118ab 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -3011,21 +3011,24 @@
InstantiateClass(SourceLocation PointOfInstantiation,
CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern,
const MultiLevelTemplateArgumentList &TemplateArgs,
- bool ExplicitInstantiation,
+ TemplateSpecializationKind TSK,
bool Complain = true);
bool
InstantiateClassTemplateSpecialization(
ClassTemplateSpecializationDecl *ClassTemplateSpec,
- bool ExplicitInstantiation, bool Complain = true);
+ TemplateSpecializationKind TSK,
+ bool Complain = true);
void InstantiateClassMembers(SourceLocation PointOfInstantiation,
CXXRecordDecl *Instantiation,
- const MultiLevelTemplateArgumentList &TemplateArgs);
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ TemplateSpecializationKind TSK);
void InstantiateClassTemplateSpecializationMembers(
SourceLocation PointOfInstantiation,
- ClassTemplateSpecializationDecl *ClassTemplateSpec);
+ ClassTemplateSpecializationDecl *ClassTemplateSpec,
+ TemplateSpecializationKind TSK);
NestedNameSpecifier *
SubstNestedNameSpecifier(NestedNameSpecifier *NNS,
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 76b6d7e..c243765 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -2934,7 +2934,8 @@
bool SpecializationRequiresInstantiation = true;
if (PrevDecl) {
- if (PrevDecl->getSpecializationKind() == TSK_ExplicitInstantiation) {
+ if (PrevDecl->getSpecializationKind()
+ == TSK_ExplicitInstantiationDefinition) {
// This particular specialization has already been declared or
// instantiated. We cannot explicitly instantiate it.
Diag(TemplateNameLoc, diag::err_explicit_instantiation_duplicate)
@@ -3028,16 +3029,19 @@
//
// This check comes when we actually try to perform the
// instantiation.
+ TemplateSpecializationKind TSK
+ = ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition
+ : TSK_ExplicitInstantiationDeclaration;
if (SpecializationRequiresInstantiation)
- InstantiateClassTemplateSpecialization(Specialization, true);
+ InstantiateClassTemplateSpecialization(Specialization, TSK);
else // Instantiate the members of this class template specialization.
- InstantiateClassTemplateSpecializationMembers(TemplateLoc, Specialization);
+ InstantiateClassTemplateSpecializationMembers(TemplateLoc, Specialization,
+ TSK);
return DeclPtrTy::make(Specialization);
}
// Explicit instantiation of a member class of a class template.
-// FIXME: Implement extern template semantics.
Sema::DeclResult
Sema::ActOnExplicitInstantiation(Scope *S,
SourceLocation ExternLoc,
@@ -3092,17 +3096,21 @@
}
}
+ TemplateSpecializationKind TSK
+ = ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition
+ : TSK_ExplicitInstantiationDeclaration;
+
if (!Record->getDefinition(Context)) {
// If the class has a definition, instantiate it (and all of its
// members, recursively).
Pattern = cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context));
if (Pattern && InstantiateClass(TemplateLoc, Record, Pattern,
getTemplateInstantiationArgs(Record),
- /*ExplicitInstantiation=*/true))
+ TSK))
return true;
} else // Instantiate all of the members of the class.
InstantiateClassMembers(TemplateLoc, Record,
- getTemplateInstantiationArgs(Record));
+ getTemplateInstantiationArgs(Record), TSK);
// FIXME: We don't have any representation for explicit instantiations of
// member classes. Such a representation is not needed for compilation, but it
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 0c47e99..55e81ae 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -623,8 +623,7 @@
/// \param TemplateArgs The template arguments to be substituted into
/// the pattern.
///
-/// \param ExplicitInstantiation whether this is an explicit instantiation
-/// (otherwise, it is an implicit instantiation).
+/// \param TSK the kind of implicit or explicit instantiation to perform.
///
/// \param Complain whether to complain if the class cannot be instantiated due
/// to the lack of a definition.
@@ -634,7 +633,7 @@
Sema::InstantiateClass(SourceLocation PointOfInstantiation,
CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern,
const MultiLevelTemplateArgumentList &TemplateArgs,
- bool ExplicitInstantiation,
+ TemplateSpecializationKind TSK,
bool Complain) {
bool Invalid = false;
@@ -650,7 +649,7 @@
Diag(Pattern->getLocation(), diag::note_member_of_template_here);
} else {
Diag(PointOfInstantiation, diag::err_template_instantiate_undefined)
- << ExplicitInstantiation
+ << (TSK != TSK_ImplicitInstantiation)
<< Context.getTypeDeclType(Instantiation);
Diag(Pattern->getLocation(), diag::note_template_decl_here);
}
@@ -708,9 +707,10 @@
Consumer.HandleTagDeclDefinition(Instantiation);
// If this is an explicit instantiation, instantiate our members, too.
- if (!Invalid && ExplicitInstantiation) {
+ if (!Invalid && TSK != TSK_ImplicitInstantiation) {
Inst.Clear();
- InstantiateClassMembers(PointOfInstantiation, Instantiation, TemplateArgs);
+ InstantiateClassMembers(PointOfInstantiation, Instantiation, TemplateArgs,
+ TSK);
}
return Invalid;
@@ -719,7 +719,7 @@
bool
Sema::InstantiateClassTemplateSpecialization(
ClassTemplateSpecializationDecl *ClassTemplateSpec,
- bool ExplicitInstantiation,
+ TemplateSpecializationKind TSK,
bool Complain) {
// Perform the actual instantiation on the canonical declaration.
ClassTemplateSpec = cast<ClassTemplateSpecializationDecl>(
@@ -798,14 +798,12 @@
}
// Note that this is an instantiation.
- ClassTemplateSpec->setSpecializationKind(
- ExplicitInstantiation? TSK_ExplicitInstantiation
- : TSK_ImplicitInstantiation);
+ ClassTemplateSpec->setSpecializationKind(TSK);
bool Result = InstantiateClass(ClassTemplateSpec->getLocation(),
ClassTemplateSpec, Pattern,
getTemplateInstantiationArgs(ClassTemplateSpec),
- ExplicitInstantiation,
+ TSK,
Complain);
for (unsigned I = 0, N = Matched.size(); I != N; ++I) {
@@ -822,8 +820,10 @@
/// or a member class of a template.
void
Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
- CXXRecordDecl *Instantiation,
- const MultiLevelTemplateArgumentList &TemplateArgs) {
+ CXXRecordDecl *Instantiation,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ TemplateSpecializationKind TSK) {
+ // FIXME: extern templates
for (DeclContext::decl_iterator D = Instantiation->decls_begin(),
DEnd = Instantiation->decls_end();
D != DEnd; ++D) {
@@ -839,7 +839,8 @@
"Missing instantiated-from-template information");
InstantiateClass(PointOfInstantiation, Record,
Record->getInstantiatedFromMemberClass(),
- TemplateArgs, true);
+ TemplateArgs,
+ TSK);
}
}
}
@@ -848,9 +849,11 @@
/// \brief Instantiate the definitions of all of the members of the
/// given class template specialization, which was named as part of an
/// explicit instantiation.
-void Sema::InstantiateClassTemplateSpecializationMembers(
+void
+Sema::InstantiateClassTemplateSpecializationMembers(
SourceLocation PointOfInstantiation,
- ClassTemplateSpecializationDecl *ClassTemplateSpec) {
+ ClassTemplateSpecializationDecl *ClassTemplateSpec,
+ TemplateSpecializationKind TSK) {
// C++0x [temp.explicit]p7:
// An explicit instantiation that names a class template
// specialization is an explicit instantion of the same kind
@@ -860,7 +863,8 @@
// containing the explicit instantiation, except as described
// below.
InstantiateClassMembers(PointOfInstantiation, ClassTemplateSpec,
- getTemplateInstantiationArgs(ClassTemplateSpec));
+ getTemplateInstantiationArgs(ClassTemplateSpec),
+ TSK);
}
Sema::OwningStmtResult
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 807115e..b63fc40 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -402,6 +402,8 @@
Decl *
TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
+ // FIXME: Dig out the out-of-line definition of this function template?
+
TemplateParameterList *TempParams = D->getTemplateParameters();
TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
@@ -496,7 +498,7 @@
D->getStorageClass(),
D->isInline(), D->hasWrittenPrototype());
Function->setLexicalDeclContext(Owner);
-
+
// Attach the parameters
for (unsigned P = 0; P < Params.size(); ++P)
Params[P]->setOwningFunction(Function);
@@ -622,7 +624,7 @@
Method->getDeclName(),
TemplateParams, Method);
if (D->isOutOfLine())
- FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
+ FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
Method->setDescribedFunctionTemplate(FunctionTemplate);
} else if (!FunctionTemplate)
Method->setInstantiationOfMemberFunction(D);
@@ -979,6 +981,15 @@
if (!Pattern)
return;
+ // C++0x [temp.explicit]p9:
+ // Except for inline functions, other explicit instantiation declarations
+ // have the effect of suppressing the implicit instantiation of the entity
+ // to which they refer.
+ if (Function->getTemplateSpecializationKind()
+ == TSK_ExplicitInstantiationDeclaration &&
+ PatternDecl->isOutOfLine() && !PatternDecl->isInline())
+ return;
+
InstantiatingTemplate Inst(*this, PointOfInstantiation, Function);
if (Inst)
return;
@@ -1080,6 +1091,8 @@
return;
}
+ // FIXME: extern templates
+
InstantiatingTemplate Inst(*this, PointOfInstantiation, Var);
if (Inst)
return;
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 11bbe4e..80cdcd5 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -1781,7 +1781,7 @@
if (Loc.isValid())
ClassTemplateSpec->setLocation(Loc);
return InstantiateClassTemplateSpecialization(ClassTemplateSpec,
- /*ExplicitInstantiation=*/false,
+ TSK_ImplicitInstantiation,
/*Complain=*/diag != 0);
}
} else if (CXXRecordDecl *Rec
@@ -1790,7 +1790,7 @@
// This record was instantiated from a class within a template.
return InstantiateClass(Loc, Rec, Pattern,
getTemplateInstantiationArgs(Rec),
- /*ExplicitInstantiation=*/false,
+ TSK_ImplicitInstantiation,
/*Complain=*/diag != 0);
}
}
diff --git a/test/CodeGenCXX/explicit-instantiation.cpp b/test/CodeGenCXX/explicit-instantiation.cpp
index 38966aa..33cbf7f 100644
--- a/test/CodeGenCXX/explicit-instantiation.cpp
+++ b/test/CodeGenCXX/explicit-instantiation.cpp
@@ -1,11 +1,17 @@
// RUN: clang-cc -emit-llvm -femit-all-decls -o %t %s &&
// RUN: grep "_ZNK4plusIillEclERKiRKl" %t | count 1
+// FIXME: We should not need the -femit-all-decls, because operator() should
+// be emitted as an external symbol rather than with linkonce_odr linkage.
+// This is a Sema problem.
template<typename T, typename U, typename Result>
struct plus {
- Result operator()(const T& t, const U& u) const {
- return t + u;
- }
+ Result operator()(const T& t, const U& u) const;
};
+template<typename T, typename U, typename Result>
+Result plus<T, U, Result>::operator()(const T& t, const U& u) const {
+ return t + u;
+}
+
template struct plus<int, long, long>;