]> granicus.if.org Git - clang/commitdiff
Fix several issues related to specializations and explicit instantiations.
authorNico Weber <nicolasweber@gmx.de>
Fri, 23 Dec 2011 20:58:04 +0000 (20:58 +0000)
committerNico Weber <nicolasweber@gmx.de>
Fri, 23 Dec 2011 20:58:04 +0000 (20:58 +0000)
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

include/clang/AST/DeclTemplate.h
lib/Sema/SemaTemplate.cpp
test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp

index f6bc41a640e890ed3b3510a6c0e1f1ef7dd9d9c7..fbf7b345accacd378dfd96bcdf2e4a4e3d3511c6 100644 (file)
@@ -1607,7 +1607,7 @@ class ClassTemplatePartialSpecializationDecl
 
 public:
   static ClassTemplatePartialSpecializationDecl *
-  Create(ASTContext &Context, TagKind TK,DeclContext *DC,
+  Create(ASTContext &Context, TagKind TK, DeclContext *DC,
          SourceLocation StartLoc, SourceLocation IdLoc,
          TemplateParameterList *Params,
          ClassTemplateDecl *SpecializedTemplate,
index d0c0f0bf2d12e15f5ca854fcff39c1e64041b4a2..b0006e6ac2a3a2a64afce3efc0ff63694207c29c 100644 (file)
@@ -5344,9 +5344,17 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
       //   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 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
     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 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
 
   // C++ [temp.expl.spec]p6:
   //   If a template, a member template or the member of a class template is
-  //   explicitly specialized then that specialization 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.
index f04c544aa4481fe5af0f68c8cf275a1eb395a874..89f343869f294fe4a08883a330b58c384ea1d5b1 100644 (file)
@@ -207,3 +207,131 @@ namespace template_class_spec_perClassDecl_nested
     static void foo();
   };
 }
+
+
+namespace spec_vs_expl_inst {
+
+  // Test all permutations of Specialization,
+  // explicit instantiation Declaration, and explicit instantiation defInition.
+
+  namespace SDI {  // PR11558
+    template <typename STRING_TYPE> class BasicStringPiece;
+    template <> class BasicStringPiece<int> { };
+    extern template class BasicStringPiece<int>;
+    template class BasicStringPiece<int>;
+  }
+
+  namespace SID {
+    template <typename STRING_TYPE> class BasicStringPiece;
+    template <> class BasicStringPiece<int> { };
+    template class BasicStringPiece<int>;  // expected-note {{explicit instantiation definition is here}}
+    extern template class BasicStringPiece<int>;  // expected-error {{explicit instantiation declaration (with 'extern') follows explicit instantiation definition (without 'extern')}}
+  }
+
+  namespace ISD {
+    template <typename STRING_TYPE> class BasicStringPiece;  // expected-note {{template is declared here}}
+    template class BasicStringPiece<int>;  // expected-error {{explicit instantiation of undefined template 'spec_vs_expl_inst::ISD::BasicStringPiece<int>'}}
+    template <> class BasicStringPiece<int> { };
+    extern template class BasicStringPiece<int>;
+  }
+
+  namespace IDS {
+    template <typename STRING_TYPE> class BasicStringPiece;  // expected-note {{template is declared here}}
+    template class BasicStringPiece<int>;  // expected-error {{explicit instantiation of undefined template 'spec_vs_expl_inst::IDS::BasicStringPiece<int>'}}  // expected-note {{explicit instantiation definition is here}}
+    extern template class BasicStringPiece<int>;  // expected-error {{explicit instantiation declaration (with 'extern') follows explicit instantiation definition (without 'extern')}}
+    template <> class BasicStringPiece<int> { };
+  }
+
+  namespace DIS {
+    template <typename STRING_TYPE> class BasicStringPiece;  // expected-note {{template is declared here}}
+    extern template class BasicStringPiece<int>;  // expected-error {{explicit instantiation of undefined template 'spec_vs_expl_inst::DIS::BasicStringPiece<int>'}}
+    template class BasicStringPiece<int>;
+    template <> class BasicStringPiece<int> { };
+  }
+
+  namespace DSI {
+    template <typename STRING_TYPE> class BasicStringPiece;  // expected-note {{template is declared here}}
+    extern template class BasicStringPiece<int>;  // expected-error {{explicit instantiation of undefined template 'spec_vs_expl_inst::DSI::BasicStringPiece<int>'}}
+    template <> class BasicStringPiece<int> { };
+    template class BasicStringPiece<int>;
+  }
+
+  // The same again, with a defined template class.
+
+  namespace SDI_WithDefinedTemplate {
+    template <typename STRING_TYPE> class BasicStringPiece {};
+    template <> class BasicStringPiece<int> { };
+    extern template class BasicStringPiece<int>;
+    template class BasicStringPiece<int>;
+  }
+
+  namespace SID_WithDefinedTemplate {
+    template <typename STRING_TYPE> class BasicStringPiece {};
+    template <> class BasicStringPiece<int> { };
+    template class BasicStringPiece<int>;  // expected-note {{explicit instantiation definition is here}}
+    extern template class BasicStringPiece<int>;  // expected-error {{explicit instantiation declaration (with 'extern') follows explicit instantiation definition (without 'extern')}}
+  }
+
+  namespace ISD_WithDefinedTemplate {
+    template <typename STRING_TYPE> class BasicStringPiece {};
+    template class BasicStringPiece<int>;  // expected-note {{explicit instantiation first required here}}
+    template <> class BasicStringPiece<int> { };  // expected-error {{explicit specialization of 'spec_vs_expl_inst::ISD_WithDefinedTemplate::BasicStringPiece<int>' after instantiation}}
+    extern template class BasicStringPiece<int>;
+  }
+
+  namespace IDS_WithDefinedTemplate {
+    template <typename STRING_TYPE> class BasicStringPiece {};
+    template class BasicStringPiece<int>;  // expected-note {{explicit instantiation definition is here}} expected-note {{previous definition is here}}
+    extern template class BasicStringPiece<int>;  // expected-error {{explicit instantiation declaration (with 'extern') follows explicit instantiation definition (without 'extern')}}
+    template <> class BasicStringPiece<int> { };  // expected-error {{redefinition of 'spec_vs_expl_inst::IDS_WithDefinedTemplate::BasicStringPiece<int>'}}
+  }
+
+  namespace DIS_WithDefinedTemplate {
+    template <typename STRING_TYPE> class BasicStringPiece {};
+    extern template class BasicStringPiece<int>;  // expected-note {{explicit instantiation first required here}}
+    template class BasicStringPiece<int>;
+    template <> class BasicStringPiece<int> { };  // expected-error {{explicit specialization of 'spec_vs_expl_inst::DIS_WithDefinedTemplate::BasicStringPiece<int>' after instantiation}}
+  }
+
+  namespace DSI_WithDefinedTemplate {
+    template <typename STRING_TYPE> class BasicStringPiece {};
+    extern template class BasicStringPiece<int>;  // expected-note {{explicit instantiation first required here}}
+    template <> class BasicStringPiece<int> { };  // expected-error {{explicit specialization of 'spec_vs_expl_inst::DSI_WithDefinedTemplate::BasicStringPiece<int>' after instantiation}}
+    template class BasicStringPiece<int>;
+  }
+
+  // And some more random tests.
+
+// FIXME: Enable this test. The error is printed fine, but the note is at some
+// weird source location that causes "previous explicit instantiation is here"
+// without anything after it to be printed. That happened before this patch too.
+//  namespace SII_WithDefinedTemplate {
+//    template <typename STRING_TYPE> class BasicStringPiece {};
+//    template <> class BasicStringPiece<int> { };
+//    template class BasicStringPiece<int>;
+//    template class BasicStringPiece<int>;
+//  }
+
+  namespace SIS {
+    template <typename STRING_TYPE> class BasicStringPiece;
+    template <> class BasicStringPiece<int> { };  // expected-note {{previous definition is here}}
+    template class BasicStringPiece<int>;
+    template <> class BasicStringPiece<int> { };  // expected-error {{redefinition of 'spec_vs_expl_inst::SIS::BasicStringPiece<int>'}}
+  }
+
+  namespace SDS {
+    template <typename STRING_TYPE> class BasicStringPiece;
+    template <> class BasicStringPiece<int> { };  // expected-note {{previous definition is here}}
+    extern template class BasicStringPiece<int>;
+    template <> class BasicStringPiece<int> { };  // expected-error {{redefinition of 'spec_vs_expl_inst::SDS::BasicStringPiece<int>'}}
+  }
+
+  namespace SDIS {
+    template <typename STRING_TYPE> class BasicStringPiece;
+    template <> class BasicStringPiece<int> { };  // expected-note {{previous definition is here}}
+    extern template class BasicStringPiece<int>;
+    template class BasicStringPiece<int>;
+    template <> class BasicStringPiece<int> { };  // expected-error {{redefinition of 'spec_vs_expl_inst::SDIS::BasicStringPiece<int>'}}
+  }
+
+}