Properly collect template arguments from a class-scope function template
authorRichard Smith <richard@metafoo.co.uk>
Tue, 10 Nov 2020 23:52:36 +0000 (15:52 -0800)
committerRichard Smith <richard@metafoo.co.uk>
Tue, 10 Nov 2020 23:55:19 +0000 (15:55 -0800)
specialization.

Fixes a crash-on-valid if further template parameters are introduced
within the specialization (by a generic lambda).

clang/lib/Sema/SemaExpr.cpp
clang/lib/Sema/SemaTemplateInstantiate.cpp
clang/test/SemaTemplate/instantiate-member-specialization.cpp [new file with mode: 0644]

index 2888395..99a3e77 100644 (file)
@@ -16800,7 +16800,11 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
         bool FirstInstantiation = PointOfInstantiation.isInvalid();
         if (FirstInstantiation) {
           PointOfInstantiation = Loc;
-          Func->setTemplateSpecializationKind(TSK, PointOfInstantiation);
+          if (auto *MSI = Func->getMemberSpecializationInfo())
+            MSI->setPointOfInstantiation(Loc);
+            // FIXME: Notify listener.
+          else
+            Func->setTemplateSpecializationKind(TSK, PointOfInstantiation);
         } else if (TSK != TSK_ImplicitInstantiation) {
           // Use the point of use as the point of instantiation, instead of the
           // point of explicit instantiation (which we track as the actual point
@@ -18040,6 +18044,7 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
         PointOfInstantiation = Loc;
         if (MSI)
           MSI->setPointOfInstantiation(PointOfInstantiation);
+          // FIXME: Notify listener.
         else
           Var->setTemplateSpecializationKind(TSK, PointOfInstantiation);
       }
index 03670e2..0b7fe0c 100644 (file)
@@ -141,7 +141,12 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
               TSK_ExplicitSpecialization)
         break;
 
-      if (const TemplateArgumentList *TemplateArgs
+      if (!RelativeToPrimary && Function->getTemplateSpecializationKind() ==
+                                    TSK_ExplicitSpecialization) {
+        // This is an implicit instantiation of an explicit specialization. We
+        // don't get any template arguments from this function but might get
+        // some from an enclosing template.
+      } else if (const TemplateArgumentList *TemplateArgs
             = Function->getTemplateSpecializationArgs()) {
         // Add the template arguments for this specialization.
         Result.addOuterTemplateArguments(TemplateArgs);
diff --git a/clang/test/SemaTemplate/instantiate-member-specialization.cpp b/clang/test/SemaTemplate/instantiate-member-specialization.cpp
new file mode 100644 (file)
index 0000000..b9bc243
--- /dev/null
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -std=c++20 -verify %s
+// expected-no-diagnostics
+
+namespace FunctionTemplate {
+  template<typename> struct S {
+    template<int> auto foo();
+
+    // Check that we don't confuse the depth-1 level-0 parameter of the generic
+    // lambda with the depth-1 level-0 parameter of the primary 'foo' template.
+    template<> constexpr auto foo<1>() {
+      return [](auto x) { return x; };
+    }
+  };
+
+  static_assert(S<void>().template foo<1>()(2) == 2);
+}