]> granicus.if.org Git - clang/commitdiff
An explicit specialization is allowed following an explicit
authorDouglas Gregor <dgregor@apple.com>
Fri, 26 Feb 2010 06:03:23 +0000 (06:03 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 26 Feb 2010 06:03:23 +0000 (06:03 +0000)
instantiation so long as that explicit specialization was declared
previously. Fixes PR6160.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@97210 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaTemplate.cpp
test/CXX/temp/temp.spec/temp.expl.spec/p6.cpp

index c98f88f86aab9d5a35dad98f288d04e0de4b85d5..c10b12b2da1065b323316f58a499b0bb7dc8f057 100644 (file)
@@ -3242,6 +3242,23 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs(
   return false;
 }
 
+/// \brief Retrieve the previous declaration of the given declaration.
+static NamedDecl *getPreviousDecl(NamedDecl *ND) {
+  if (VarDecl *VD = dyn_cast<VarDecl>(ND))
+    return VD->getPreviousDeclaration();
+  if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND))
+    return FD->getPreviousDeclaration();
+  if (TagDecl *TD = dyn_cast<TagDecl>(ND))
+    return TD->getPreviousDeclaration();
+  if (TypedefDecl *TD = dyn_cast<TypedefDecl>(ND))
+    return TD->getPreviousDeclaration();
+  if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(ND))
+    return FTD->getPreviousDeclaration();
+  if (ClassTemplateDecl *CTD = dyn_cast<ClassTemplateDecl>(ND))
+    return CTD->getPreviousDeclaration();
+  return 0;
+}
+
 Sema::DeclResult
 Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
                                        TagUseKind TUK,
@@ -3547,15 +3564,26 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
   //   instantiation to take place, in every translation unit in which such a 
   //   use occurs; no diagnostic is required.
   if (PrevDecl && PrevDecl->getPointOfInstantiation().isValid()) {
-    SourceRange Range(TemplateNameLoc, RAngleLoc);
-    Diag(TemplateNameLoc, diag::err_specialization_after_instantiation)
-      << Context.getTypeDeclType(Specialization) << Range;
+    bool Okay = false;
+    for (NamedDecl *Prev = PrevDecl; Prev; Prev = getPreviousDecl(Prev)) {
+      // Is there any previous explicit specialization declaration?
+      if (getTemplateSpecializationKind(Prev) == TSK_ExplicitSpecialization) {
+        Okay = true;
+        break;
+      }
+    }
+
+    if (!Okay) {
+      SourceRange Range(TemplateNameLoc, RAngleLoc);
+      Diag(TemplateNameLoc, diag::err_specialization_after_instantiation)
+        << Context.getTypeDeclType(Specialization) << Range;
 
-    Diag(PrevDecl->getPointOfInstantiation(), 
-         diag::note_instantiation_required_here)
-      << (PrevDecl->getTemplateSpecializationKind() 
+      Diag(PrevDecl->getPointOfInstantiation(), 
+           diag::note_instantiation_required_here)
+        << (PrevDecl->getTemplateSpecializationKind() 
                                                 != TSK_ImplicitInstantiation);
-    return true;
+      return true;
+    }
   }
   
   // If this is not a friend, note that this is an explicit specialization.
@@ -3728,6 +3756,12 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
       //   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.
+      for (NamedDecl *Prev = PrevDecl; Prev; Prev = getPreviousDecl(Prev)) {
+        // Is there any previous explicit specialization declaration?
+        if (getTemplateSpecializationKind(Prev) == TSK_ExplicitSpecialization)
+          return false;
+      }
+
       Diag(NewLoc, diag::err_specialization_after_instantiation)
         << PrevDecl;
       Diag(PrevPointOfInstantiation, diag::note_instantiation_required_here)
index 34c3710e04c5b860531ef7253761fa8759f0a815..f5394713968811785e4daf6a12d612a40b9adf1a 100644 (file)
@@ -54,3 +54,10 @@ void f(Array<String>& v) {
 
 template<> void sort<String>(Array<String>& v); // // expected-error{{after instantiation}}
 template<> void sort<>(Array<char*>& v);       // OK: sort<char*> not yet used
+
+namespace PR6160 {
+  template<typename T> void f(T);
+  template<> void f(int);
+  extern template void f(int);
+  template<> void f(int) { }
+}