mirror of
https://github.com/intel/llvm.git
synced 2026-01-26 21:53:12 +08:00
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:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
59
clang/test/CXX/temp/temp.spec/temp.explicit/p9.cpp
Normal file
59
clang/test/CXX/temp/temp.spec/temp.explicit/p9.cpp
Normal 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}}
|
||||
}
|
||||
Reference in New Issue
Block a user