]> granicus.if.org Git - clang/commitdiff
PR19340: If we see a declaration of a member of an unspecialized class template
authorRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 17 Apr 2014 03:52:20 +0000 (03:52 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 17 Apr 2014 03:52:20 +0000 (03:52 +0000)
that looks like it might be an explicit specialization, don't recover as an
explicit specialization (bypassing the check that would reject that).

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

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaTemplate.cpp
test/SemaTemplate/explicit-specialization-member.cpp

index 180e088d39b21e993c1c9cc599a8ef86121fb6bc..c13be0326edbb86d72acfd96a91ef852ca7ef0a2 100644 (file)
@@ -3267,8 +3267,8 @@ 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">;
+  "cannot specialize %select{|(with 'template<>') }0a member of an "
+  "unspecialized template">;
 
 // C++ Class Template Partial Specialization
 def err_default_arg_in_partial_spec : Error<
index 58742fc055e463f1d0349566108be41fdb055ce4..2ef144f15871a29eea955911fb9e8db90ea024b2 100644 (file)
@@ -1721,6 +1721,38 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
   //   template<> for each enclosing class template that is
   //   explicitly specialized.
   bool SawNonEmptyTemplateParameterList = false;
+
+  auto CheckExplicitSpecialization = [&](SourceRange Range,
+                                         bool Recovery = false) {
+    if (SawNonEmptyTemplateParameterList) {
+      Diag(DeclLoc, diag::err_specialize_member_of_template)
+        << !Recovery << Range;
+      Invalid = true;
+      IsExplicitSpecialization = false;
+      return true;
+    }
+
+    return false;
+  };
+
+  auto DiagnoseMissingExplicitSpecialization = [&] (SourceRange Range) {
+    // Check that we can have an explicit specialization here.
+    if (CheckExplicitSpecialization(Range, true))
+      return true;
+
+    // We don't have a template header, but we should.
+    SourceLocation ExpectedTemplateLoc;
+    if (!ParamLists.empty())
+      ExpectedTemplateLoc = ParamLists[0]->getTemplateLoc();
+    else
+      ExpectedTemplateLoc = DeclStartLoc;
+
+    Diag(DeclLoc, diag::err_template_spec_needs_header)
+      << Range
+      << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> ");
+    return false;
+  };
+
   unsigned ParamIdx = 0;
   for (unsigned TypeIdx = 0, NumTypes = NestedTypes.size(); TypeIdx != NumTypes;
        ++TypeIdx) {
@@ -1791,13 +1823,8 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
     //   are not explicitly specialized as well.
     if (ParamIdx < ParamLists.size()) {
       if (ParamLists[ParamIdx]->size() == 0) {
-        if (SawNonEmptyTemplateParameterList) {
-          Diag(DeclLoc, diag::err_specialize_member_of_template)
-            << ParamLists[ParamIdx]->getSourceRange();
-          Invalid = true;
-          IsExplicitSpecialization = false;
+        if (CheckExplicitSpecialization(ParamLists[ParamIdx]->getSourceRange()))
           return 0;
-        }
       } else
         SawNonEmptyTemplateParameterList = true;
     }
@@ -1820,29 +1847,20 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
           Invalid = true;
           return 0;
         }
-        
+
         // Consume this template header.
         ++ParamIdx;
         continue;
-      } 
-      
-      if (!IsFriend) {
-        // We don't have a template header, but we should.
-        SourceLocation ExpectedTemplateLoc;
-        if (!ParamLists.empty())
-          ExpectedTemplateLoc = ParamLists[0]->getTemplateLoc();
-        else
-          ExpectedTemplateLoc = DeclStartLoc;
-
-        // FIXME: Don't recover this way if we SawNonEmptyTemplateParameterList.
-        Diag(DeclLoc, diag::err_template_spec_needs_header)
-          << getRangeOfTypeInNestedNameSpecifier(Context, T, SS)
-          << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> ");
       }
-      
+
+      if (!IsFriend)
+        if (DiagnoseMissingExplicitSpecialization(
+                getRangeOfTypeInNestedNameSpecifier(Context, T, SS)))
+          return 0;
+
       continue;
     }
-    
+
     if (NeedNonemptyTemplateHeader) {
       // In friend declarations we can have template-ids which don't
       // depend on the corresponding template parameter lists.  But
@@ -1886,18 +1904,11 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
   // the declaration itself.
   if (ParamIdx >= ParamLists.size()) {
     if (TemplateId && !IsFriend) {
-      // FIXME: Don't recover this way if we SawNonEmptyTemplateParameterList.
       // We don't have a template header for the declaration itself, but we
       // should.
-      SourceLocation ExpectedTemplateLoc;
-      if (!ParamLists.empty())
-        ExpectedTemplateLoc = ParamLists[0]->getTemplateLoc();
-      else
-        ExpectedTemplateLoc = DeclStartLoc;
-      Diag(DeclLoc, diag::err_template_spec_needs_header)
-          << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc)
-          << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> ");
       IsExplicitSpecialization = true;
+      DiagnoseMissingExplicitSpecialization(SourceRange(TemplateId->LAngleLoc,
+                                                        TemplateId->RAngleLoc));
 
       // Fabricate an empty template parameter list for the invented header.
       return TemplateParameterList::Create(Context, SourceLocation(),
@@ -1947,14 +1958,10 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
   //   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.back()->size() == 0 && SawNonEmptyTemplateParameterList) {
-    Diag(DeclLoc, diag::err_specialize_member_of_template)
-      << ParamLists[ParamIdx]->getSourceRange();
-    Invalid = true;
-    IsExplicitSpecialization = false;
+  if (ParamLists.back()->size() == 0 &&
+      CheckExplicitSpecialization(ParamLists[ParamIdx]->getSourceRange()))
     return 0;
-  }
-  
+
   // Return the last template parameter list, which corresponds to the
   // entity being declared.
   return ParamLists.back();
index 07d73894468fdcbf284991a7aeb53af08274c3fb..e8dc4d219acbc2b0e0d4d271898de71475b8132c 100644 (file)
@@ -38,12 +38,22 @@ namespace PR18246 {
 
   template<typename T>
   template<int N>
-  void Baz<T>::bar() {
+  void Baz<T>::bar() { // expected-note {{couldn't infer template argument 'N'}}
   }
 
-  // FIXME: Don't suggest the 'template<>' correction here, because this cannot
-  // be an explicit specialization.
+  // FIXME: We shouldn't try to match this against a prior declaration if
+  // template parameter matching failed.
   template<typename T>
-  void Baz<T>::bar<0>() { // expected-error {{requires 'template<>'}}
+  void Baz<T>::bar<0>() { // expected-error {{cannot specialize a member of an unspecialized template}} \
+                          // expected-error {{no function template matches}}
   }
 }
+
+namespace PR19340 {
+template<typename T> struct Helper {
+  template<int N> static void func(const T *m) {} // expected-note {{failed template argument deduction}}
+};
+
+template<typename T> void Helper<T>::func<2>() {} // expected-error {{cannot specialize a member}} \
+                                                  // expected-error {{no function template matches}}
+}