Keep track of whether a member function instantiated from a member

function of a class template was implicitly instantiated, explicitly
instantiated (declaration or definition), or explicitly
specialized. The same MemberSpecializationInfo structure will be used
for static data members and member classes as well.

llvm-svn: 83509
This commit is contained in:
Douglas Gregor 2009-10-07 23:56:10 +00:00
parent 32cc4ec304
commit d801b06232
7 changed files with 104 additions and 42 deletions

View File

@ -27,6 +27,7 @@ class Stmt;
class CompoundStmt;
class StringLiteral;
class TemplateArgumentList;
class MemberSpecializationInfo;
class FunctionTemplateSpecializationInfo;
class TypeLoc;
@ -830,14 +831,15 @@ private:
/// For non-templates, this value will be NULL. For function
/// declarations that describe a function template, this will be a
/// pointer to a FunctionTemplateDecl. For member functions
/// of class template specializations, this will be the
/// FunctionDecl from which the member function was instantiated.
/// of class template specializations, this will be a MemberSpecializationInfo
/// pointer containing information about the specialization.
/// For function template specializations, this will be a
/// FunctionTemplateSpecializationInfo, which contains information about
/// the template being specialized and the template arguments involved in
/// that specialization.
llvm::PointerUnion3<FunctionTemplateDecl*, FunctionDecl*,
FunctionTemplateSpecializationInfo*>
llvm::PointerUnion3<FunctionTemplateDecl *,
MemberSpecializationInfo *,
FunctionTemplateSpecializationInfo *>
TemplateOrSpecialization;
protected:
@ -1063,15 +1065,12 @@ public:
/// the FunctionDecl X<T>::A. When a complete definition of
/// X<int>::A is required, it will be instantiated from the
/// declaration returned by getInstantiatedFromMemberFunction().
FunctionDecl *getInstantiatedFromMemberFunction() const {
return TemplateOrSpecialization.dyn_cast<FunctionDecl*>();
}
FunctionDecl *getInstantiatedFromMemberFunction() const;
/// \brief Specify that this record is an instantiation of the
/// member function RD.
void setInstantiationOfMemberFunction(FunctionDecl *RD) {
TemplateOrSpecialization = RD;
}
/// member function FD.
void setInstantiationOfMemberFunction(FunctionDecl *FD,
TemplateSpecializationKind TSK);
/// \brief Retrieves the function template that is described by this
/// function declaration.

View File

@ -548,6 +548,33 @@ public:
}
};
/// \brief Provides information a specialization of a member of a class
/// template, which may be a member function, static data member, or
/// member class.
class MemberSpecializationInfo {
NamedDecl *InstantiatedFrom;
TemplateSpecializationKind TSK;
public:
explicit
MemberSpecializationInfo(NamedDecl *IF, TemplateSpecializationKind TSK)
: InstantiatedFrom(IF), TSK(TSK) { }
/// \brief Retrieve the member declaration from which this member was
/// instantiated.
NamedDecl *getInstantiatedFrom() const { return InstantiatedFrom; }
/// \brief Determine what kind of template specialization this is.
TemplateSpecializationKind getTemplateSpecializationKind() const {
return TSK;
}
/// \brief Set the template specialization kind.
void setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
this->TSK = TSK;
}
};
/// Declaration of a template function.
class FunctionTemplateDecl : public TemplateDecl {
protected:

View File

@ -410,6 +410,16 @@ void FunctionDecl::Destroy(ASTContext& C) {
for (param_iterator I=param_begin(), E=param_end(); I!=E; ++I)
(*I)->Destroy(C);
FunctionTemplateSpecializationInfo *FTSInfo
= TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
if (FTSInfo)
C.Deallocate(FTSInfo);
MemberSpecializationInfo *MSInfo
= TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>();
if (MSInfo)
C.Deallocate(MSInfo);
C.Deallocate(ParamInfo);
Decl::Destroy(C);
@ -670,6 +680,24 @@ OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const {
return OO_None;
}
FunctionDecl *FunctionDecl::getInstantiatedFromMemberFunction() const {
if (MemberSpecializationInfo *Info
= TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>())
return cast<FunctionDecl>(Info->getInstantiatedFrom());
return 0;
}
void
FunctionDecl::setInstantiationOfMemberFunction(FunctionDecl *FD,
TemplateSpecializationKind TSK) {
assert(TemplateOrSpecialization.isNull() &&
"Member function is already a specialization");
MemberSpecializationInfo *Info
= new (getASTContext()) MemberSpecializationInfo(FD, TSK);
TemplateOrSpecialization = Info;
}
FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const {
if (FunctionTemplateSpecializationInfo *Info
= TemplateOrSpecialization
@ -727,32 +755,30 @@ FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context,
TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const {
// For a function template specialization, query the specialization
// information object.
FunctionTemplateSpecializationInfo *Info
FunctionTemplateSpecializationInfo *FTSInfo
= TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
if (Info)
return Info->getTemplateSpecializationKind();
if (FTSInfo)
return FTSInfo->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();
MemberSpecializationInfo *MSInfo
= TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>();
if (MSInfo)
return MSInfo->getTemplateSpecializationKind();
return TSK_Undeclared;
}
void
FunctionDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
FunctionTemplateSpecializationInfo *Info
= TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
assert(Info && "Not a function template specialization");
Info->setTemplateSpecializationKind(TSK);
if (FunctionTemplateSpecializationInfo *FTSInfo
= TemplateOrSpecialization.dyn_cast<
FunctionTemplateSpecializationInfo*>())
FTSInfo->setTemplateSpecializationKind(TSK);
else if (MemberSpecializationInfo *MSInfo
= TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>())
MSInfo->setTemplateSpecializationKind(TSK);
else
assert(false && "Function cannot have a template specialization kind");
}
bool FunctionDecl::isOutOfLine() const {

View File

@ -3171,10 +3171,13 @@ Sema::CheckMemberFunctionSpecialization(CXXMethodDecl *FD,
Instantiation, FD->getLocation(),
false, TSK_ExplicitSpecialization))
return true;
// FIXME: Check for specialization-after-instantiation errors and such.
// FIXME: Mark the new declaration as a member function specialization.
// We may also want to mark the original instantiation as having been
// explicitly specialized.
// Note that this function is an explicit instantiation of a member function.
Instantiation->setTemplateSpecializationKind(TSK_ExplicitSpecialization);
FD->setInstantiationOfMemberFunction(FunctionInTemplate,
TSK_ExplicitSpecialization);
// Save the caller the trouble of having to figure out which declaration
// this specialization matches.

View File

@ -977,6 +977,8 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
DEnd = Instantiation->decls_end();
D != DEnd; ++D) {
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(*D)) {
if (Function->getInstantiatedFromMemberFunction())
Function->setTemplateSpecializationKind(TSK);
if (!Function->getBody() && TSK != TSK_ExplicitInstantiationDeclaration)
InstantiateFunctionDefinition(PointOfInstantiation, Function);
} else if (VarDecl *Var = dyn_cast<VarDecl>(*D)) {
@ -984,14 +986,19 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
TSK != TSK_ExplicitInstantiationDeclaration)
InstantiateStaticDataMemberDefinition(PointOfInstantiation, Var);
} else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(*D)) {
if (!Record->isInjectedClassName() && !Record->getDefinition(Context)) {
assert(Record->getInstantiatedFromMemberClass() &&
"Missing instantiated-from-template information");
if (Record->isInjectedClassName())
continue;
assert(Record->getInstantiatedFromMemberClass() &&
"Missing instantiated-from-template information");
if (!Record->getDefinition(Context))
InstantiateClass(PointOfInstantiation, Record,
Record->getInstantiatedFromMemberClass(),
TemplateArgs,
TSK);
}
else
InstantiateClassMembers(PointOfInstantiation, Record, TemplateArgs,
TSK);
}
}
}

View File

@ -522,7 +522,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) {
if (!Owner->isDependentContext())
DC->makeDeclVisibleInContext(Function, /* Recoverable = */ false);
Function->setInstantiationOfMemberFunction(D);
Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
}
if (InitFunctionInstantiation(Function, D))
@ -637,7 +637,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
Method->setDescribedFunctionTemplate(FunctionTemplate);
} else if (!FunctionTemplate)
Method->setInstantiationOfMemberFunction(D);
Method->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
// If we are instantiating a member function defined
// out-of-line, the instantiation will have the same lexical

View File

@ -31,11 +31,11 @@ void test_intptr(X0<int*> xi, X0<int*>::Inner xii) {
// FIXME: we would like the notes to point to the explicit instantiation at the
// bottom.
extern template class X0<long*>; // expected-note{{instantiation}}
extern template class X0<long*>; // expected-note 2{{instantiation}}
void test_longptr(X0<long*> xl, X0<long*>::Inner xli) {
xl.f(0);
xli.g(0); // expected-note{{instantiation}}
xli.g(0);
}
template class X0<long*>;