Explicit instantiation suppresses the instantiation of non-inline

function template specializations and member functions of class
template specializations.

llvm-svn: 85300
This commit is contained in:
Douglas Gregor
2009-10-27 20:53:28 +00:00
parent cde65ec581
commit afca3b4a5c
5 changed files with 131 additions and 21 deletions

View File

@@ -1123,7 +1123,17 @@ public:
return TemplateOrSpecialization.
dyn_cast<FunctionTemplateSpecializationInfo*>();
}
/// \brief Determines whether this function is a function template
/// specialization or a member of a class template specialization that can
/// be implicitly instantiated.
bool isImplicitlyInstantiable() const;
/// \brief Retrieve the function declaration from which this function could
/// be instantiated, if it is an instantiation (rather than a non-template
/// or a specialization, for example).
FunctionDecl *getTemplateInstantiationPattern() const;
/// \brief Retrieve the primary template that this function template
/// specialization either specializes or was instantiated from.
///
@@ -1176,7 +1186,7 @@ public:
/// instantiated from a template; otherwie, returns an invalid source
/// location.
SourceLocation getPointOfInstantiation() const;
/// \brief Determine whether this is or was instantiated from an out-of-line
/// definition of a member function.
bool isOutOfLine() const;

View File

@@ -753,6 +753,60 @@ FunctionDecl::setInstantiationOfMemberFunction(FunctionDecl *FD,
TemplateOrSpecialization = Info;
}
bool FunctionDecl::isImplicitlyInstantiable() const {
// If this function already has a definition or is invalid, it can't be
// implicitly instantiated.
if (isInvalidDecl() || getBody())
return false;
switch (getTemplateSpecializationKind()) {
case TSK_Undeclared:
case TSK_ExplicitSpecialization:
case TSK_ExplicitInstantiationDefinition:
return false;
case TSK_ImplicitInstantiation:
return true;
case TSK_ExplicitInstantiationDeclaration:
// Handled below.
break;
}
// Find the actual template from which we will instantiate.
const FunctionDecl *PatternDecl = getTemplateInstantiationPattern();
Stmt *Pattern = 0;
if (PatternDecl)
Pattern = PatternDecl->getBody(PatternDecl);
// 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 (!Pattern || !PatternDecl)
return true;
return PatternDecl->isInline() ||
(isa<CXXMethodDecl>(PatternDecl) && !PatternDecl->isOutOfLine());
}
FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const {
if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) {
while (Primary->getInstantiatedFromMemberTemplate()) {
// If we have hit a point where the user provided a specialization of
// this template, we're done looking.
if (Primary->isMemberSpecialization())
break;
Primary = Primary->getInstantiatedFromMemberTemplate();
}
return Primary->getTemplatedDecl();
}
return getInstantiatedFromMemberFunction();
}
FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const {
if (FunctionTemplateSpecializationInfo *Info
= TemplateOrSpecialization

View File

@@ -6295,21 +6295,21 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
// Implicit instantiation of function templates and member functions of
// class templates.
if (!Function->getBody() &&
Function->getTemplateSpecializationKind()
== TSK_ImplicitInstantiation) {
if (!Function->getBody() && Function->isImplicitlyInstantiable()) {
bool AlreadyInstantiated = false;
if (FunctionTemplateSpecializationInfo *SpecInfo
= Function->getTemplateSpecializationInfo()) {
if (SpecInfo->getPointOfInstantiation().isInvalid())
SpecInfo->setPointOfInstantiation(Loc);
else
else if (SpecInfo->getTemplateSpecializationKind()
== TSK_ImplicitInstantiation)
AlreadyInstantiated = true;
} else if (MemberSpecializationInfo *MSInfo
= Function->getMemberSpecializationInfo()) {
if (MSInfo->getPointOfInstantiation().isInvalid())
MSInfo->setPointOfInstantiation(Loc);
else
else if (MSInfo->getTemplateSpecializationKind()
== TSK_ImplicitInstantiation)
AlreadyInstantiated = true;
}

View File

@@ -1097,20 +1097,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
return;
// Find the function body that we'll be substituting.
const FunctionDecl *PatternDecl = 0;
if (FunctionTemplateDecl *Primary = Function->getPrimaryTemplate()) {
while (Primary->getInstantiatedFromMemberTemplate()) {
// If we have hit a point where the user provided a specialization of
// this template, we're done looking.
if (Primary->isMemberSpecialization())
break;
Primary = Primary->getInstantiatedFromMemberTemplate();
}
PatternDecl = Primary->getTemplatedDecl();
} else
PatternDecl = Function->getInstantiatedFromMemberFunction();
const FunctionDecl *PatternDecl = Function->getTemplateInstantiationPattern();
Stmt *Pattern = 0;
if (PatternDecl)
Pattern = PatternDecl->getBody(PatternDecl);

View File

@@ -0,0 +1,59 @@
// RUN: clang-cc -fsyntax-only -std=c++0x -verify %s
template<typename T>
struct X0 {
void f(T &t) {
t = 1; // expected-error{{incompatible type}}
}
void g(T &t);
void h(T &t);
static T static_var;
};
template<typename T>
inline void X0<T>::g(T & t) {
t = 1; // expected-error{{incompatible type}}
}
template<typename T>
void X0<T>::h(T & t) {
t = 1;
}
template<typename T>
T X0<T>::static_var = 1;
extern template struct X0<int*>;
int *&test(X0<int*> xi, int *ip) {
xi.f(ip); // expected-note{{instantiation}}
xi.g(ip); // expected-note{{instantiation}}
xi.h(ip);
return X0<int*>::static_var;
}
template<typename T>
void f0(T& t) {
t = 1; // expected-error{{incompatible type}}
}
template<typename T>
inline void f1(T& t) {
t = 1; // expected-error 2{{incompatible type}}
}
extern template void f0<>(int *&);
extern template void f1<>(int *&);
void test_f0(int *ip, float *fp) {
f0(ip);
f0(fp); // expected-note{{instantiation}}
}
void test_f1(int *ip, float *fp) {
f1(ip); // expected-note{{instantiation}}
f1(fp); // expected-note{{instantiation}}
}