diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-10-27 20:53:28 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-10-27 20:53:28 +0000 |
commit | 3b846b6c252972a6f142aa226c1e65aebd0feeca (patch) | |
tree | a27f8e9f4d856ce94d5611cefeacb31f88e3a016 | |
parent | 82cac29c6ed3121c00845bd2ea84232061bd7dbf (diff) |
Explicit instantiation suppresses the instantiation of non-inline
function template specializations and member functions of class
template specializations.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@85300 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/Decl.h | 14 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 54 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 10 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 15 | ||||
-rw-r--r-- | test/CXX/temp/temp.spec/temp.explicit/p9.cpp | 59 |
5 files changed, 131 insertions, 21 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 8071aba7c5..8efd552716 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -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; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 38eb3371fe..7b0a84c397 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -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 diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 5c3f5e7bd1..f4e58f07f8 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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; } diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index c9319c58ae..8606fb034b 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -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); diff --git a/test/CXX/temp/temp.spec/temp.explicit/p9.cpp b/test/CXX/temp/temp.spec/temp.explicit/p9.cpp new file mode 100644 index 0000000000..a53113fb96 --- /dev/null +++ b/test/CXX/temp/temp.spec/temp.explicit/p9.cpp @@ -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}} +} |