Implicit instantiation for function template specializations.

For a FunctionDecl that has been instantiated due to template argument
deduction, we now store the primary template from which it was
instantiated and the deduced template arguments. From this
information, we can instantiate the body of the function template.

llvm-svn: 74232
This commit is contained in:
Douglas Gregor
2009-06-26 00:10:03 +00:00
parent 4ac764d72e
commit 4adbc6d947
9 changed files with 124 additions and 22 deletions

View File

@@ -25,7 +25,8 @@ class FunctionTemplateDecl;
class Stmt;
class CompoundStmt;
class StringLiteral;
class TemplateArgumentList;
/// TranslationUnitDecl - The top declaration context.
class TranslationUnitDecl : public Decl, public DeclContext {
TranslationUnitDecl()
@@ -614,10 +615,17 @@ public:
None, Extern, Static, PrivateExtern
};
private:
/// \brief Provides information about a function template specialization,
/// which is a FunctionDecl that has been explicitly specialization or
/// instantiated from a function template.
struct TemplateSpecializationInfo {
FunctionTemplateDecl *Template;
const TemplateArgumentList *TemplateArguments;
};
/// ParamInfo - new[]'d array of pointers to VarDecls for the formal
/// parameters of this function. This is null if a prototype or if there are
/// no formals. TODO: we could allocate this space immediately after the
/// FunctionDecl object to save an allocation like FunctionType does.
/// no formals.
ParmVarDecl **ParamInfo;
LazyDeclStmtPtr Body;
@@ -664,8 +672,12 @@ private:
/// pointer to a FunctionTemplateDecl. For member functions
/// of class template specializations, this will be the
/// FunctionDecl from which the member function was instantiated.
llvm::PointerUnion<FunctionTemplateDecl*, FunctionDecl*>
TemplateOrInstantiation;
/// 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*,
TemplateSpecializationInfo*> TemplateOrSpecialization;
protected:
FunctionDecl(Kind DK, DeclContext *DC, SourceLocation L,
@@ -678,7 +690,7 @@ protected:
SClass(S), IsInline(isInline), C99InlineDefinition(false),
IsVirtualAsWritten(false), IsPure(false), HasInheritedPrototype(false),
HasWrittenPrototype(true), IsDeleted(false), TypeSpecStartLoc(TSSL),
EndRangeLoc(L), TemplateOrInstantiation() {}
EndRangeLoc(L), TemplateOrSpecialization() {}
virtual ~FunctionDecl() {}
virtual void Destroy(ASTContext& C);
@@ -887,13 +899,13 @@ public:
/// X<int>::A is required, it will be instantiated from the
/// declaration returned by getInstantiatedFromMemberFunction().
FunctionDecl *getInstantiatedFromMemberFunction() const {
return TemplateOrInstantiation.dyn_cast<FunctionDecl*>();
return TemplateOrSpecialization.dyn_cast<FunctionDecl*>();
}
/// \brief Specify that this record is an instantiation of the
/// member function RD.
void setInstantiationOfMemberFunction(FunctionDecl *RD) {
TemplateOrInstantiation = RD;
TemplateOrSpecialization = RD;
}
/// \brief Retrieves the function template that is described by this
@@ -909,13 +921,54 @@ public:
/// getDescribedFunctionTemplate() retrieves the
/// FunctionTemplateDecl from a FunctionDecl.
FunctionTemplateDecl *getDescribedFunctionTemplate() const {
return TemplateOrInstantiation.dyn_cast<FunctionTemplateDecl*>();
return TemplateOrSpecialization.dyn_cast<FunctionTemplateDecl*>();
}
void setDescribedFunctionTemplate(FunctionTemplateDecl *Template) {
TemplateOrInstantiation = Template;
TemplateOrSpecialization = Template;
}
/// \brief Retrieve the primary template that this function template
/// specialization either specializes or was instantiated from.
///
/// If this function declaration is not a function template specialization,
/// returns NULL.
FunctionTemplateDecl *getPrimaryTemplate() const {
if (TemplateSpecializationInfo *Info
= TemplateOrSpecialization.dyn_cast<TemplateSpecializationInfo*>()) {
return Info->Template;
}
return 0;
}
/// \brief Retrieve the template arguments used to produce this function
/// template specialization from the primary template.
///
/// If this function declaration is not a function template specialization,
/// returns NULL.
const TemplateArgumentList *getTemplateSpecializationArgs() const {
if (TemplateSpecializationInfo *Info
= TemplateOrSpecialization.dyn_cast<TemplateSpecializationInfo*>()) {
return Info->TemplateArguments;
}
return 0;
}
/// \brief Specify that this function declaration is actually a function
/// template specialization.
///
/// \param Context the AST context in which this function resides.
///
/// \param Template the function template that this function template
/// specialization specializes.
///
/// \param TemplateArgs the template arguments that produced this
/// function template specialization from the template.
void setFunctionTemplateSpecialization(ASTContext &Context,
FunctionTemplateDecl *Template,
const TemplateArgumentList *TemplateArgs);
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) {
return D->getKind() >= FunctionFirst && D->getKind() <= FunctionLast;

View File

@@ -153,7 +153,7 @@ protected:
NamedDecl *TemplatedDecl;
TemplateParameterList* TemplateParams;
};
/// Declaration of a template function.
class FunctionTemplateDecl : public TemplateDecl {
protected:

View File

@@ -821,6 +821,9 @@ def note_template_member_class_here : Note<
"in instantiation of member class %0 requested here">;
def note_template_member_function_here : Note<
"in instantiation of member function %q0 requested here">;
def note_function_template_spec_here : Note<
"in instantiation of function template specialization %q0 requested here">;
def note_default_arg_instantiation_here : Note<
"in instantiation of default argument for '%0' required here">;
def note_partial_spec_deduct_instantiation_here : Note<

View File

@@ -359,6 +359,10 @@ void FunctionDecl::Destroy(ASTContext& C) {
C.Deallocate(ParamInfo);
if (TemplateSpecializationInfo *Info
= TemplateOrSpecialization.dyn_cast<TemplateSpecializationInfo*>())
C.Deallocate(Info);
Decl::Destroy(C);
}
@@ -555,6 +559,20 @@ OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const {
return OO_None;
}
void
FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context,
FunctionTemplateDecl *Template,
const TemplateArgumentList *TemplateArgs) {
TemplateSpecializationInfo *Info
= TemplateOrSpecialization.dyn_cast<TemplateSpecializationInfo*>();
if (!Info)
Info = new (Context) TemplateSpecializationInfo;
Info->Template = Template;
Info->TemplateArguments = TemplateArgs;
TemplateOrSpecialization = Info;
}
//===----------------------------------------------------------------------===//
// TagDecl Implementation
//===----------------------------------------------------------------------===//

View File

@@ -5566,12 +5566,15 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
}
}
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
// Implicit instantiation of function templates
// Implicit instantiation of function templates and member functions of
// class templates.
if (!Function->getBody(Context)) {
if (Function->getInstantiatedFromMemberFunction())
// FIXME: distinguish between implicit instantiations of function
// templates and explicit specializations (the latter don't get
// instantiated, naturally).
if (Function->getInstantiatedFromMemberFunction() ||
Function->getPrimaryTemplate())
PendingImplicitInstantiations.push(std::make_pair(Function, Loc));
// FIXME: check for function template specializations.
}

View File

@@ -870,6 +870,10 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
if (!Specialization || Trap.hasErrorOccurred())
return TDK_SubstitutionFailure;
// Turn the specialization into an actual function template specialization.
Specialization->setFunctionTemplateSpecialization(Context,
FunctionTemplate,
Info.take());
return TDK_Success;
}

View File

@@ -29,10 +29,18 @@ using namespace clang;
/// instantiate the given declaration.
const TemplateArgumentList &
Sema::getTemplateInstantiationArgs(NamedDecl *D) {
// Template arguments for a class template specialization.
if (ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(D))
return Spec->getTemplateArgs();
// Template arguments for a function template specialization.
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D))
if (const TemplateArgumentList *TemplateArgs
= Function->getTemplateSpecializationArgs())
return *TemplateArgs;
// Template arguments for a member of a class template specialization.
DeclContext *EnclosingTemplateCtx = D->getDeclContext();
while (!isa<ClassTemplateSpecializationDecl>(EnclosingTemplateCtx)) {
assert(!EnclosingTemplateCtx->isFileContext() &&
@@ -158,8 +166,11 @@ void Sema::PrintInstantiationStack() {
<< Active->InstantiationRange;
} else {
FunctionDecl *Function = cast<FunctionDecl>(D);
unsigned DiagID = diag::note_template_member_function_here;
// FIXME: check for a function template
unsigned DiagID;
if (Function->getPrimaryTemplate())
DiagID = diag::note_function_template_spec_here;
else
DiagID = diag::note_template_member_function_here;
Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
DiagID)
<< Function

View File

@@ -645,16 +645,17 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New,
/// function.
void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
FunctionDecl *Function) {
// FIXME: make this work for function template specializations, too.
if (Function->isInvalidDecl())
return;
assert(!Function->getBody(Context) && "Already instantiated!");
// Find the function body that we'll be substituting.
const FunctionDecl *PatternDecl
= Function->getInstantiatedFromMemberFunction();
const FunctionDecl *PatternDecl = 0;
if (FunctionTemplateDecl *Primary = Function->getPrimaryTemplate())
PatternDecl = Primary->getTemplatedDecl();
else
PatternDecl = Function->getInstantiatedFromMemberFunction();
Stmt *Pattern = 0;
if (PatternDecl)
Pattern = PatternDecl->getBody(Context, PatternDecl);

View File

@@ -1,5 +1,4 @@
// RUN: clang-cc -fsyntax-only -verify %s
template<typename T, typename U>
struct X {
T f(T x, U y) { return x + y; }
@@ -14,3 +13,13 @@ void test(X<int, int> *xii, X<int*, int> *xpi, X<int, int*> *xip) {
(void)xip->g(2, 0); // okay: does not instantiate
}
template<typename T, typename U>
T add(T t, U u) {
return t + u; // expected-error{{invalid operands}}
}
void test_add(char *cp, int i, int *ip) {
char* cp2 = add(cp, i);
add(cp, cp); // expected-note{{instantiation of}}
(void)sizeof(add(ip, ip));
}