Fix several issues related to specializations and explicit instantiations.

Explicit instantiations following specializations are no-ops and hence have
no PointOfInstantiation. That was done correctly in most cases, but for a
specialization -> instantiation decl -> instantiation definition chain, the
definition didn't realize that it was a no-op. Fix that.

Also, when printing diagnostics for these no-ops, get the diag location from
the decl name location.

Add many test cases, one of them not yet passing (but it failed the same way
before this change). Fixes http://llvm.org/pr11558 and more.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147225 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index d0c0f0b..b0006e6 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -5344,9 +5344,17 @@
       //   translation unit, the definition shall follow the declaration.
       Diag(NewLoc,
            diag::err_explicit_instantiation_declaration_after_definition);
-      Diag(PrevPointOfInstantiation,
-           diag::note_explicit_instantiation_definition_here);
-      assert(PrevPointOfInstantiation.isValid() &&
+
+      // Explicit instantiations following a specialization have no effect and
+      // hence no PrevPointOfInstantiation. In that case, walk decl backwards
+      // until a valid name loc is found.
+      SourceLocation PrevDiagLoc = PrevPointOfInstantiation;
+      for (NamedDecl *Prev = PrevDecl; Prev && !PrevDiagLoc.isValid();
+          Prev = getPreviousDecl(Prev)) {
+        PrevDiagLoc = Prev->getLocation();
+      }
+      Diag(PrevDiagLoc, diag::note_explicit_instantiation_definition_here);
+      assert(PrevDiagLoc.isValid() &&
              "Explicit instantiation without point of instantiation?");
       HasNoEffect = true;
       return false;
@@ -5383,6 +5391,20 @@
     case TSK_ExplicitInstantiationDeclaration:
       // We're explicity instantiating a definition for something for which we
       // were previously asked to suppress instantiations. That's fine.
+
+      // C++0x [temp.explicit]p4:
+      //   For a given set of template parameters, if an explicit instantiation
+      //   of a template appears after a declaration of an explicit
+      //   specialization for that template, the explicit instantiation has no
+      //   effect.
+      for (NamedDecl *Prev = PrevDecl; Prev; Prev = getPreviousDecl(Prev)) {
+        // Is there any previous explicit specialization declaration?
+        if (getTemplateSpecializationKind(Prev) == TSK_ExplicitSpecialization) {
+          HasNoEffect = true;
+          break;
+        }
+      }
+
       return false;
 
     case TSK_ExplicitInstantiationDefinition:
@@ -5677,7 +5699,7 @@
 
   // C++ [temp.expl.spec]p6:
   //   If a template, a member template or the member of a class template is
-  //   explicitly specialized then that spe- cialization shall be declared
+  //   explicitly specialized then that specialization shall be declared
   //   before the first use of that specialization that would cause an implicit
   //   instantiation to take place, in every translation unit in which such a
   //   use occurs; no diagnostic is required.