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.
 

llvm-svn: 81053
This commit is contained in:
Douglas Gregor 2009-09-04 22:48:11 +00:00
parent 21d15aa591
commit 34ec2ef159
10 changed files with 143 additions and 91 deletions

View File

@ -715,6 +715,29 @@ public:
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,13 +1100,13 @@ public:
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) {

View File

@ -510,9 +510,8 @@ public:
/// \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.
@ -521,13 +520,16 @@ public:
/// \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 Determine what kind of template specialization this is.
TemplateSpecializationKind getTemplateSpecializationKind() const {
return (TemplateSpecializationKind)(Template.getInt() + 1);
}
/// \brief Set whether this is an explicit specialization or an implicit
/// instantiation.
void setExplicitSpecialization(bool ES) {
Template.setInt(ES);
/// \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 @@ public:
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 @@ class ClassTemplateSpecializationDecl
/// \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 @@ public:
ClassTemplatePartialSpecializationDecl *>
getInstantiatedFrom() const {
if (getSpecializationKind() != TSK_ImplicitInstantiation &&
getSpecializationKind() != TSK_ExplicitInstantiation)
getSpecializationKind() != TSK_ExplicitInstantiationDefinition &&
getSpecializationKind() != TSK_ExplicitInstantiationDeclaration)
return (ClassTemplateDecl*)0;
if (SpecializedPartialSpecialization *PartialSpec

View File

@ -640,7 +640,7 @@ FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context,
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 @@ FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context,
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);
}
//===----------------------------------------------------------------------===//

View File

@ -251,8 +251,7 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD,
// inline or static.
CodeGenModule::GVALinkage External = CodeGenModule::GVA_StrongExternal;
if (Context.getLangOptions().CPlusPlus &&
(FD->getPrimaryTemplate() || FD->getInstantiatedFromMemberFunction()) &&
!FD->isExplicitSpecialization())
FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
External = CodeGenModule::GVA_TemplateInstantiation;
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {

View File

@ -3011,21 +3011,24 @@ public:
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,

View File

@ -2934,7 +2934,8 @@ Sema::ActOnExplicitInstantiation(Scope *S,
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 @@ Sema::ActOnExplicitInstantiation(Scope *S,
//
// 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 @@ Sema::ActOnExplicitInstantiation(Scope *S,
}
}
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

View File

@ -623,8 +623,7 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
/// \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 @@ bool
Sema::InstantiateClass(SourceLocation PointOfInstantiation,
CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern,
const MultiLevelTemplateArgumentList &TemplateArgs,
bool ExplicitInstantiation,
TemplateSpecializationKind TSK,
bool Complain) {
bool Invalid = false;
@ -650,7 +649,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
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 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
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 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
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 @@ Sema::InstantiateClassTemplateSpecialization(
}
// 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) {
@ -823,7 +821,9 @@ Sema::InstantiateClassTemplateSpecialization(
void
Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
CXXRecordDecl *Instantiation,
const MultiLevelTemplateArgumentList &TemplateArgs) {
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 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
"Missing instantiated-from-template information");
InstantiateClass(PointOfInstantiation, Record,
Record->getInstantiatedFromMemberClass(),
TemplateArgs, true);
TemplateArgs,
TSK);
}
}
}
@ -848,9 +849,11 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
/// \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 @@ void Sema::InstantiateClassTemplateSpecializationMembers(
// containing the explicit instantiation, except as described
// below.
InstantiateClassMembers(PointOfInstantiation, ClassTemplateSpec,
getTemplateInstantiationArgs(ClassTemplateSpec));
getTemplateInstantiationArgs(ClassTemplateSpec),
TSK);
}
Sema::OwningStmtResult

View File

@ -402,6 +402,8 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
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)
@ -979,6 +981,15 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
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 @@ void Sema::InstantiateStaticDataMemberDefinition(
return;
}
// FIXME: extern templates
InstantiatingTemplate Inst(*this, PointOfInstantiation, Var);
if (Inst)
return;

View File

@ -1781,7 +1781,7 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
if (Loc.isValid())
ClassTemplateSpec->setLocation(Loc);
return InstantiateClassTemplateSpecialization(ClassTemplateSpec,
/*ExplicitInstantiation=*/false,
TSK_ImplicitInstantiation,
/*Complain=*/diag != 0);
}
} else if (CXXRecordDecl *Rec
@ -1790,7 +1790,7 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
// This record was instantiated from a class within a template.
return InstantiateClass(Loc, Rec, Pattern,
getTemplateInstantiationArgs(Rec),
/*ExplicitInstantiation=*/false,
TSK_ImplicitInstantiation,
/*Complain=*/diag != 0);
}
}

View File

@ -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>;