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

View File

@ -410,6 +410,16 @@ void FunctionDecl::Destroy(ASTContext& C) {
for (param_iterator I=param_begin(), E=param_end(); I!=E; ++I) for (param_iterator I=param_begin(), E=param_end(); I!=E; ++I)
(*I)->Destroy(C); (*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); C.Deallocate(ParamInfo);
Decl::Destroy(C); Decl::Destroy(C);
@ -670,6 +680,24 @@ OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const {
return OO_None; 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 { FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const {
if (FunctionTemplateSpecializationInfo *Info if (FunctionTemplateSpecializationInfo *Info
= TemplateOrSpecialization = TemplateOrSpecialization
@ -727,32 +755,30 @@ FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context,
TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const { TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const {
// For a function template specialization, query the specialization // For a function template specialization, query the specialization
// information object. // information object.
FunctionTemplateSpecializationInfo *Info FunctionTemplateSpecializationInfo *FTSInfo
= TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>(); = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
if (Info) if (FTSInfo)
return Info->getTemplateSpecializationKind(); return FTSInfo->getTemplateSpecializationKind();
if (!getInstantiatedFromMemberFunction()) MemberSpecializationInfo *MSInfo
return TSK_Undeclared; = TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>();
if (MSInfo)
// Find the class template specialization corresponding to this instantiation return MSInfo->getTemplateSpecializationKind();
// of a member function.
const DeclContext *Parent = getDeclContext(); return TSK_Undeclared;
while (Parent && !isa<ClassTemplateSpecializationDecl>(Parent))
Parent = Parent->getParent();
if (!Parent)
return TSK_Undeclared;
return cast<ClassTemplateSpecializationDecl>(Parent)->getSpecializationKind();
} }
void void
FunctionDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) { FunctionDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
FunctionTemplateSpecializationInfo *Info if (FunctionTemplateSpecializationInfo *FTSInfo
= TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>(); = TemplateOrSpecialization.dyn_cast<
assert(Info && "Not a function template specialization"); FunctionTemplateSpecializationInfo*>())
Info->setTemplateSpecializationKind(TSK); 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 { bool FunctionDecl::isOutOfLine() const {

View File

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

View File

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

View File

@ -522,7 +522,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) {
if (!Owner->isDependentContext()) if (!Owner->isDependentContext())
DC->makeDeclVisibleInContext(Function, /* Recoverable = */ false); DC->makeDeclVisibleInContext(Function, /* Recoverable = */ false);
Function->setInstantiationOfMemberFunction(D); Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
} }
if (InitFunctionInstantiation(Function, D)) if (InitFunctionInstantiation(Function, D))
@ -637,7 +637,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext()); FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
Method->setDescribedFunctionTemplate(FunctionTemplate); Method->setDescribedFunctionTemplate(FunctionTemplate);
} else if (!FunctionTemplate) } else if (!FunctionTemplate)
Method->setInstantiationOfMemberFunction(D); Method->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
// If we are instantiating a member function defined // If we are instantiating a member function defined
// out-of-line, the instantiation will have the same lexical // 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 // FIXME: we would like the notes to point to the explicit instantiation at the
// bottom. // 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) { void test_longptr(X0<long*> xl, X0<long*>::Inner xli) {
xl.f(0); xl.f(0);
xli.g(0); // expected-note{{instantiation}} xli.g(0);
} }
template class X0<long*>; template class X0<long*>;