Slight improvement for extern templates, so that an explicit
instantiation definition can follow an explicit instantiation
declaration. This is as far as I want to go with extern templates now,
but they will still need quite a bit more work to get all of the C++0x
semantics right.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@81573 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 4df55e6..509f45c 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -6123,6 +6123,7 @@
     // Implicit instantiation of static data members of class templates.
     // FIXME: distinguish between implicit instantiations (which we need to
     // actually instantiate) and explicit specializations.
+    // FIXME: extern templates
     if (Var->isStaticDataMember() &&
         Var->getInstantiatedFromStaticDataMember())
       PendingImplicitInstantiations.push_back(std::make_pair(Var, Loc));
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 8bb33eb..f8b48b2 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -2977,7 +2977,7 @@
                                                   Converted, 0);
       Specialization->setLexicalDeclContext(CurContext);
       CurContext->addDecl(Specialization);
-      return DeclPtrTy::make(Specialization);
+      return DeclPtrTy::make(PrevDecl);
     }
 
     // If we have already (implicitly) instantiated this
@@ -2985,14 +2985,19 @@
     if (PrevDecl->getSpecializationKind() == TSK_ImplicitInstantiation)
       SpecializationRequiresInstantiation = false;
 
-    // Since the only prior class template specialization with these
-    // arguments was referenced but not declared, reuse that
-    // declaration node as our own, updating its source location to
-    // reflect our new declaration.
-    Specialization = PrevDecl;
-    Specialization->setLocation(TemplateNameLoc);
-    PrevDecl = 0;
-  } else {
+    if (PrevDecl->getSpecializationKind() == TSK_ImplicitInstantiation ||
+        PrevDecl->getSpecializationKind() == TSK_Undeclared) {
+      // Since the only prior class template specialization with these
+      // arguments was referenced but not declared, reuse that
+      // declaration node as our own, updating its source location to
+      // reflect our new declaration.
+      Specialization = PrevDecl;
+      Specialization->setLocation(TemplateNameLoc);
+      PrevDecl = 0;
+    }
+  } 
+  
+  if (!Specialization) {
     // Create a new class template specialization declaration node for
     // this explicit specialization.
     Specialization
@@ -3000,10 +3005,17 @@
                                              ClassTemplate->getDeclContext(),
                                                 TemplateNameLoc,
                                                 ClassTemplate,
-                                                Converted, 0);
+                                                Converted, PrevDecl);
 
-    ClassTemplate->getSpecializations().InsertNode(Specialization,
-                                                   InsertPos);
+    if (PrevDecl) {
+      // Remove the previous declaration from the folding set, since we want
+      // to introduce a new declaration.
+      ClassTemplate->getSpecializations().RemoveNode(PrevDecl);
+      ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos);
+    } 
+    
+    // Insert the new specialization.
+    ClassTemplate->getSpecializations().InsertNode(Specialization, InsertPos);
   }
 
   // Build the fully-sugared type for this explicit instantiation as
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 6a52352..adc8a94 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -820,11 +820,28 @@
   ClassTemplateSpec = cast<ClassTemplateSpecializationDecl>(
                                          ClassTemplateSpec->getCanonicalDecl());
 
-  // We can only instantiate something that hasn't already been
-  // instantiated or specialized. Fail without any diagnostics: our
-  // caller will provide an error message.
-  if (ClassTemplateSpec->getSpecializationKind() != TSK_Undeclared)
+  // Check whether we have already instantiated or specialized this class
+  // template specialization.
+  if (ClassTemplateSpec->getSpecializationKind() != TSK_Undeclared) {
+    if (ClassTemplateSpec->getSpecializationKind() == 
+          TSK_ExplicitInstantiationDeclaration &&
+        TSK == TSK_ExplicitInstantiationDefinition) {
+      // An explicit instantiation definition follows an explicit instantiation
+      // declaration (C++0x [temp.explicit]p10); go ahead and perform the
+      // explicit instantiation.
+      ClassTemplateSpec->setSpecializationKind(TSK);
+      InstantiateClassTemplateSpecializationMembers(
+                        /*FIXME?*/ClassTemplateSpec->getPointOfInstantiation(), 
+                                  ClassTemplateSpec,
+                                  TSK);
+      return false;
+    }
+    
+    // We can only instantiate something that hasn't already been
+    // instantiated or specialized. Fail without any diagnostics: our
+    // caller will provide an error message.    
     return true;
+  }
 
   ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate();
   CXXRecordDecl *Pattern = 0;
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index f0597be..dbb5661 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1031,6 +1031,9 @@
   // Instantiate the function body.
   OwningStmtResult Body = SubstStmt(Pattern, TemplateArgs);
 
+  if (Body.isInvalid())
+    Function->setInvalidDecl();
+  
   ActOnFinishFunctionBody(DeclPtrTy::make(Function), move(Body),
                           /*IsInstantiation=*/true);
 
diff --git a/test/SemaTemplate/extern-templates.cpp b/test/SemaTemplate/extern-templates.cpp
index 3a13d11..4589570 100644
--- a/test/SemaTemplate/extern-templates.cpp
+++ b/test/SemaTemplate/extern-templates.cpp
@@ -1,4 +1,4 @@
-// RUN: clang-cc -fsyntax-only %s
+// RUN: clang-cc -fsyntax-only -verify %s
 
 template<typename T>
 class X0 {
@@ -12,7 +12,7 @@
 
 template<typename T>
 void X0<T>::f(T t) {
-  t = 17;
+  t = 17; // expected-error{{incompatible}}
 }
 
 extern template class X0<int>;
@@ -21,10 +21,21 @@
 
 template<typename T>
 void X0<T>::Inner::g(T t) {
-  t = 17;
+  t = 17; // expected-error{{incompatible}}
 }
 
 void test_intptr(X0<int*> xi, X0<int*>::Inner xii) {
   xi.f(0);
   xii.g(0);
 }
+
+// FIXME: we would like the notes to point to the explicit instantiation at the
+// bottom.
+extern template class X0<long*>; // expected-note{{instantiation}}
+
+void test_longptr(X0<long*> xl, X0<long*>::Inner xli) {
+  xl.f(0);
+  xli.g(0); // expected-note{{instantiation}}
+}
+
+template class X0<long*>;