r206444 - PR19340: If we see a declaration of a member of an unspecialized class template

Richard Smith richard-llvm at metafoo.co.uk
Wed Apr 16 20:52:21 PDT 2014


Author: rsmith
Date: Wed Apr 16 22:52:20 2014
New Revision: 206444

URL: http://llvm.org/viewvc/llvm-project?rev=206444&view=rev
Log:
PR19340: If we see a declaration of a member of an unspecialized class template
that looks like it might be an explicit specialization, don't recover as an
explicit specialization (bypassing the check that would reject that).

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

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=206444&r1=206443&r2=206444&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Apr 16 22:52:20 2014
@@ -3267,8 +3267,8 @@ def err_template_qualified_declarator_no
   "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<

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=206444&r1=206443&r2=206444&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Apr 16 22:52:20 2014
@@ -1721,6 +1721,38 @@ TemplateParameterList *Sema::MatchTempla
   //   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::MatchTempla
     //   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::MatchTempla
           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::MatchTempla
   // 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::MatchTempla
   //   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();

Modified: cfe/trunk/test/SemaTemplate/explicit-specialization-member.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/explicit-specialization-member.cpp?rev=206444&r1=206443&r2=206444&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/explicit-specialization-member.cpp (original)
+++ cfe/trunk/test/SemaTemplate/explicit-specialization-member.cpp Wed Apr 16 22:52:20 2014
@@ -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}}
+}





More information about the cfe-commits mailing list