[cfe-commits] r85300 - in /cfe/trunk: include/clang/AST/Decl.h lib/AST/Decl.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/CXX/temp/temp.spec/temp.explicit/p9.cpp

Douglas Gregor dgregor at apple.com
Tue Oct 27 13:53:28 PDT 2009


Author: dgregor
Date: Tue Oct 27 15:53:28 2009
New Revision: 85300

URL: http://llvm.org/viewvc/llvm-project?rev=85300&view=rev
Log:
Explicit instantiation suppresses the instantiation of non-inline
function template specializations and member functions of class
template specializations.


Added:
    cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p9.cpp
Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/lib/AST/Decl.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=85300&r1=85299&r2=85300&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Tue Oct 27 15:53:28 2009
@@ -1123,7 +1123,17 @@
     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 @@
   /// 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;

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=85300&r1=85299&r2=85300&view=diff

==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Tue Oct 27 15:53:28 2009
@@ -753,6 +753,60 @@
   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

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=85300&r1=85299&r2=85300&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Oct 27 15:53:28 2009
@@ -6295,21 +6295,21 @@
   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;
       }
       

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=85300&r1=85299&r2=85300&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Tue Oct 27 15:53:28 2009
@@ -1097,20 +1097,7 @@
     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);

Added: cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p9.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p9.cpp?rev=85300&view=auto

==============================================================================
--- cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p9.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p9.cpp Tue Oct 27 15:53:28 2009
@@ -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}}
+}





More information about the cfe-commits mailing list