arphaman created this revision.

This patch fixes an an assertion that previously occurred for the following 
sample:

  template <typename InputT, typename OutputT>
  struct SourceSelectionRequirement {
  
    template<typename T>
    OutputT evaluateSelectionRequirement(InputT &&Value) {
    }
  };
  
  template <typename InputT, typename OutputT>
  OutputT SourceSelectionRequirement<InputT, 
OutputT>::evaluateSelectionRequirement<void>(InputT &&Value) {
      return Value;
  }

Clang asserted when it was trying to deduce the function template 
specialisation for `evaluateSelectionRequirement`, because it was trying to do 
deduction with the template specialisation `<void>` and `template <typename 
InputT, typename OutputT>` which have different template depth.

I initially fixed the issue by setting the right depth, during the deduction, 
but wasn't happy with the results (we produced two errors, the second one 
complained about failed deduction). Thus I changed my approach to the one 
that's presented in this patch - we can detect if the template parameters are 
fabricated and then avoid the deduction. This approach avoids the second error 
while fixing the assertion. It also fixed a redundant error `FIXME` in 
`SemaTemplate/explicit-specialization-member.cpp` (Basically removed a 
redundant deduction error).

Thanks for taking a look


Repository:
  rL LLVM

https://reviews.llvm.org/D37341

Files:
  lib/Sema/SemaDecl.cpp
  test/SemaTemplate/deduction-crash.cpp
  test/SemaTemplate/explicit-specialization-member.cpp


Index: test/SemaTemplate/explicit-specialization-member.cpp
===================================================================
--- test/SemaTemplate/explicit-specialization-member.cpp
+++ test/SemaTemplate/explicit-specialization-member.cpp
@@ -38,24 +38,20 @@
 
   template<typename T>
   template<int N>
-  void Baz<T>::bar() { // expected-note {{couldn't infer template argument 
'N'}}
+  void Baz<T>::bar() {
   }
 
-  // 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 {{cannot specialize a member of an 
unspecialized template}} \
-                          // expected-error {{no function template matches}}
+  void Baz<T>::bar<0>() { // expected-error {{cannot specialize a member of an 
unspecialized template}}
   }
 }
 
 namespace PR19340 {
 template<typename T> struct Helper {
-  template<int N> static void func(const T *m) {} // expected-note {{failed 
template argument deduction}}
+  template<int N> static void func(const T *m) {}
 };
 
-template<typename T> void Helper<T>::func<2>() {} // expected-error {{cannot 
specialize a member}} \
-                                                  // expected-error {{no 
function template matches}}
+template<typename T> void Helper<T>::func<2>() {} // expected-error {{cannot 
specialize a member}}
 }
 
 namespace SpecLoc {
Index: test/SemaTemplate/deduction-crash.cpp
===================================================================
--- test/SemaTemplate/deduction-crash.cpp
+++ test/SemaTemplate/deduction-crash.cpp
@@ -144,3 +144,20 @@
   template<typename T, typename U = void> int n<T *>; // expected-error +{{}} 
expected-note {{}}
   int k = n<void *>;
 }
+
+namespace deduceFunctionSpecializationForInvalidOutOfLineFunction {
+
+template <typename InputT, typename OutputT>
+struct SourceSelectionRequirement {
+  template<typename T>
+  OutputT evaluateSelectionRequirement(InputT &&Value) {
+  }
+};
+
+template <typename InputT, typename OutputT>
+OutputT SourceSelectionRequirement<InputT, OutputT>::
+evaluateSelectionRequirement<void>(InputT &&Value) { // expected-error 
{{cannot specialize a member of an unspecialized template}}
+  return Value;
+}
+
+}
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -8195,6 +8195,7 @@
   FunctionTemplateDecl *FunctionTemplate = nullptr;
   bool isMemberSpecialization = false;
   bool isFunctionTemplateSpecialization = false;
+  bool HasFabricatedTemplateSpecializationTemplateParams = false;
 
   bool isDependentClassScopeExplicitSpecialization = false;
   bool HasExplicitTemplateArgs = false;
@@ -8303,6 +8304,8 @@
       } else {
         // This is a function template specialization.
         isFunctionTemplateSpecialization = true;
+        if (Invalid && TemplateParams->getLAngleLoc().isInvalid())
+          HasFabricatedTemplateSpecializationTemplateParams = true;
         // For source fidelity, store all the template param lists.
         if (TemplateParamLists.size() > 0)
           NewFD->setTemplateParameterListsInfo(Context, TemplateParamLists);
@@ -8874,7 +8877,8 @@
           diag::ext_function_specialization_in_class :
           diag::err_function_specialization_in_class)
           << NewFD->getDeclName();
-      } else if (CheckFunctionTemplateSpecialization(NewFD,
+      } else if (!HasFabricatedTemplateSpecializationTemplateParams &&
+                 CheckFunctionTemplateSpecialization(NewFD,
                                   (HasExplicitTemplateArgs ? &TemplateArgs
                                                            : nullptr),
                                                      Previous))


Index: test/SemaTemplate/explicit-specialization-member.cpp
===================================================================
--- test/SemaTemplate/explicit-specialization-member.cpp
+++ test/SemaTemplate/explicit-specialization-member.cpp
@@ -38,24 +38,20 @@
 
   template<typename T>
   template<int N>
-  void Baz<T>::bar() { // expected-note {{couldn't infer template argument 'N'}}
+  void Baz<T>::bar() {
   }
 
-  // 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 {{cannot specialize a member of an unspecialized template}} \
-                          // expected-error {{no function template matches}}
+  void Baz<T>::bar<0>() { // expected-error {{cannot specialize a member of an unspecialized template}}
   }
 }
 
 namespace PR19340 {
 template<typename T> struct Helper {
-  template<int N> static void func(const T *m) {} // expected-note {{failed template argument deduction}}
+  template<int N> static void func(const T *m) {}
 };
 
-template<typename T> void Helper<T>::func<2>() {} // expected-error {{cannot specialize a member}} \
-                                                  // expected-error {{no function template matches}}
+template<typename T> void Helper<T>::func<2>() {} // expected-error {{cannot specialize a member}}
 }
 
 namespace SpecLoc {
Index: test/SemaTemplate/deduction-crash.cpp
===================================================================
--- test/SemaTemplate/deduction-crash.cpp
+++ test/SemaTemplate/deduction-crash.cpp
@@ -144,3 +144,20 @@
   template<typename T, typename U = void> int n<T *>; // expected-error +{{}} expected-note {{}}
   int k = n<void *>;
 }
+
+namespace deduceFunctionSpecializationForInvalidOutOfLineFunction {
+
+template <typename InputT, typename OutputT>
+struct SourceSelectionRequirement {
+  template<typename T>
+  OutputT evaluateSelectionRequirement(InputT &&Value) {
+  }
+};
+
+template <typename InputT, typename OutputT>
+OutputT SourceSelectionRequirement<InputT, OutputT>::
+evaluateSelectionRequirement<void>(InputT &&Value) { // expected-error {{cannot specialize a member of an unspecialized template}}
+  return Value;
+}
+
+}
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -8195,6 +8195,7 @@
   FunctionTemplateDecl *FunctionTemplate = nullptr;
   bool isMemberSpecialization = false;
   bool isFunctionTemplateSpecialization = false;
+  bool HasFabricatedTemplateSpecializationTemplateParams = false;
 
   bool isDependentClassScopeExplicitSpecialization = false;
   bool HasExplicitTemplateArgs = false;
@@ -8303,6 +8304,8 @@
       } else {
         // This is a function template specialization.
         isFunctionTemplateSpecialization = true;
+        if (Invalid && TemplateParams->getLAngleLoc().isInvalid())
+          HasFabricatedTemplateSpecializationTemplateParams = true;
         // For source fidelity, store all the template param lists.
         if (TemplateParamLists.size() > 0)
           NewFD->setTemplateParameterListsInfo(Context, TemplateParamLists);
@@ -8874,7 +8877,8 @@
           diag::ext_function_specialization_in_class :
           diag::err_function_specialization_in_class)
           << NewFD->getDeclName();
-      } else if (CheckFunctionTemplateSpecialization(NewFD,
+      } else if (!HasFabricatedTemplateSpecializationTemplateParams &&
+                 CheckFunctionTemplateSpecialization(NewFD,
                                   (HasExplicitTemplateArgs ? &TemplateArgs
                                                            : nullptr),
                                                      Previous))
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D37341: [Sema] Fi... Alex Lorenz via Phabricator via cfe-commits

Reply via email to