]> granicus.if.org Git - clang/commitdiff
Diagnose the condition in C++ [temp.expl.spec]p16 that prohibits
authorDouglas Gregor <dgregor@apple.com>
Mon, 6 Jun 2011 15:22:55 +0000 (15:22 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 6 Jun 2011 15:22:55 +0000 (15:22 +0000)
specializing a member of an unspecialized template, and recover from
such errors without crashing. Fixes PR10024 / <rdar://problem/9509761>.

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

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaDecl.cpp
lib/Sema/SemaTemplate.cpp
test/CXX/temp/temp.spec/temp.expl.spec/p16.cpp

index e7c9a16972f3e90fc81767b5f3d64815ba2b8784..38c011dcc5c2b59c6c8c4c532c662421fd27cdc8 100644 (file)
@@ -1893,6 +1893,9 @@ def note_explicit_template_spec_does_not_need_header : Note<
 def err_template_qualified_declarator_no_match : Error<
   "nested name specifier '%0' for declaration does not refer into a class, "
   "class template or class template partial specialization">;
+def err_specialize_member_of_template : Error<
+  "cannot specialize (with 'template<>') a member of an unspecialized "
+  "template">;
 
 // C++ Class Template Partial Specialization
 def err_default_arg_in_partial_spec : Error<
index 5de1838b9f7476c60a25d36360d5dc3acb6f5647..e1872c2d7dbf3a8bf34aee8be37254c3c3ed087c 100644 (file)
@@ -4516,8 +4516,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
 
   if (!getLangOptions().CPlusPlus) {
     // Perform semantic checking on the function declaration.
-    bool isExplctSpecialization=false;
-    CheckFunctionDeclaration(S, NewFD, Previous, isExplctSpecialization,
+    bool isExplicitSpecialization=false;
+    CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization,
                              Redeclaration);
     assert((NewFD->isInvalidDecl() || !Redeclaration ||
             Previous.getResultKind() != LookupResult::FoundOverloaded) &&
@@ -4540,7 +4540,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
     
       HasExplicitTemplateArgs = true;
     
-      if (FunctionTemplate) {
+      if (NewFD->isInvalidDecl()) {
+        HasExplicitTemplateArgs = false;
+      } else if (FunctionTemplate) {
         // Function template with explicit template arguments.
         Diag(D.getIdentifierLoc(), diag::err_function_template_partial_spec)
           << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc);
index 3761740d8c038480a43c69c3452279c7c634dd75..8213f3266f1ff3883ce465954aafa9566b6f342f 100644 (file)
@@ -1610,6 +1610,7 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
   //   such a member, the member declaration shall be preceded by a
   //   template<> for each enclosing class template that is
   //   explicitly specialized.
+  bool SawNonEmptyTemplateParameterList = false;
   unsigned ParamIdx = 0;
   for (unsigned TypeIdx = 0, NumTypes = NestedTypes.size(); TypeIdx != NumTypes;
        ++TypeIdx) {
@@ -1671,6 +1672,26 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
       NeedNonemptyTemplateHeader = false;
     } 
     
+    // C++ [temp.expl.spec]p16:
+    //   In an explicit specialization declaration for a member of a class 
+    //   template or a member template that ap- pears in namespace scope, the 
+    //   member template and some of its enclosing class templates may remain 
+    //   unspecialized, except that the declaration shall not explicitly 
+    //   specialize a class member template if its en- closing class templates 
+    //   are not explicitly specialized as well.
+    if (ParamIdx < NumParamLists) {
+      if (ParamLists[ParamIdx]->size() == 0) {
+        if (SawNonEmptyTemplateParameterList) {
+          Diag(DeclLoc, diag::err_specialize_member_of_template)
+            << ParamLists[ParamIdx]->getSourceRange();
+          Invalid = true;
+          IsExplicitSpecialization = false;
+          return 0;
+        }
+      } else
+        SawNonEmptyTemplateParameterList = true;
+    }
+    
     if (NeedEmptyTemplateHeader) {
       // If we're on the last of the types, and we need a 'template<>' header
       // here, then it's an explicit specialization.
@@ -1787,6 +1808,22 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
       Invalid = true;
   }
 
+  // C++ [temp.expl.spec]p16:
+  //   In an explicit specialization declaration for a member of a class 
+  //   template or a member template that ap- pears in namespace scope, the 
+  //   member template and some of its enclosing class templates may remain 
+  //   unspecialized, except that the declaration shall not explicitly 
+  //   specialize a class member template if its en- closing class templates 
+  //   are not explicitly specialized as well.
+  if (ParamLists[NumParamLists - 1]->size() == 0 && 
+      SawNonEmptyTemplateParameterList) {
+    Diag(DeclLoc, diag::err_specialize_member_of_template)
+      << ParamLists[ParamIdx]->getSourceRange();
+    Invalid = true;
+    IsExplicitSpecialization = false;
+    return 0;
+  }
+  
   // Return the last template parameter list, which corresponds to the
   // entity being declared.
   return ParamLists[NumParamLists - 1];
index 2f9a3cbf945770e94b2a8f4eccbce2e05d21b06b..c7597e9f817cac0a345019fc31285e590cc48451 100644 (file)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
 template<class T> struct A { 
   void f(T);
   template<class X1> void g1(T, X1); 
@@ -24,3 +24,15 @@ template<> template<>
                                     // member specialization even if defined in class definition
 
 template<> void A<int>::h(int) { }
+
+namespace PR10024 {
+  template <typename T> 
+  struct Test{ 
+    template <typename U> 
+    void get(U i) {}
+  }; 
+
+  template <typename T>
+  template <>
+  void Test<T>::get<double>(double i) {}  // expected-error{{cannot specialize (with 'template<>') a member of an unspecialized template}}
+}