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
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 38eb337..7b0a84c 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -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
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 5c3f5e7..f4e58f0 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -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;
       }
       
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index c9319c5..8606fb0 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -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);