https://github.com/mizvekov created 
https://github.com/llvm/llvm-project/pull/111457

Clang previously missed implementing the historical rule 
https://eel.is/c++draft/temp.arg.template#3.sentence-3 for deduced function 
template calls.

This patch implements this rule, but only on the
'frelaxed-template-template-args' mode, which is
currently the default.

As its negation is deprecated and will be removed soon, this patch does not 
change the implementation in that case.

WIP, as it's missing some changes which will help in not breaking compatibility 
in overload resolution.

>From 1e8fbca963bb13d38ee6f9907ca8e5039bd08a8d Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <mizve...@gmail.com>
Date: Sat, 5 Oct 2024 21:56:51 -0300
Subject: [PATCH] [clang] WIP: Implement TTP 'reversed' pack matching for
 deduced function template calls.

Clang previously missed implementing the historical rule
https://eel.is/c++draft/temp.arg.template#3.sentence-3
for deduced function template calls.

This patch implements this rule, but only on the
'frelaxed-template-template-args' patch, which is
currently the default mode.

As it's negation is deprecated and will be removed soon,
this patch does not change the implementation there.

WIP, as it's missing some changes which will help in not breaking
compatibility in overload resolution.
---
 clang/include/clang/Sema/Sema.h          | 14 +++--
 clang/lib/Sema/SemaLookup.cpp            |  1 +
 clang/lib/Sema/SemaOverload.cpp          |  5 +-
 clang/lib/Sema/SemaTemplate.cpp          | 23 +++----
 clang/lib/Sema/SemaTemplateDeduction.cpp | 76 ++++++++++++++----------
 clang/test/SemaTemplate/cwg2398.cpp      | 34 +++++++++++
 6 files changed, 102 insertions(+), 51 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 5d38862ce59f0c..05857884fdc2e1 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11636,7 +11636,7 @@ class Sema final : public SemaBase {
                         SourceLocation RAngleLoc, unsigned ArgumentPackIndex,
                         SmallVectorImpl<TemplateArgument> &SugaredConverted,
                         SmallVectorImpl<TemplateArgument> &CanonicalConverted,
-                        CheckTemplateArgumentKind CTAK,
+                        CheckTemplateArgumentKind CTAK, bool PartialOrdering,
                         bool *MatchedPackOnParmToNonPackOnArg);
 
   /// Check that the given template arguments can be provided to
@@ -11719,7 +11719,8 @@ class Sema final : public SemaBase {
   /// It returns true if an error occurred, and false otherwise.
   bool CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
                                      TemplateParameterList *Params,
-                                     TemplateArgumentLoc &Arg, bool IsDeduced,
+                                     TemplateArgumentLoc &Arg,
+                                     bool PartialOrdering,
                                      bool *MatchedPackOnParmToNonPackOnArg);
 
   void NoteTemplateLocation(const NamedDecl &Decl,
@@ -12231,8 +12232,8 @@ class Sema final : public SemaBase {
       SmallVectorImpl<DeducedTemplateArgument> &Deduced,
       unsigned NumExplicitlySpecified, FunctionDecl *&Specialization,
       sema::TemplateDeductionInfo &Info,
-      SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs = nullptr,
-      bool PartialOverloading = false,
+      SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs,
+      bool PartialOverloading, bool PartialOrdering,
       llvm::function_ref<bool()> CheckNonDependent = [] { return false; });
 
   /// Perform template argument deduction from a function call
@@ -12266,7 +12267,8 @@ class Sema final : public SemaBase {
       TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
       FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info,
       bool PartialOverloading, bool AggregateDeductionCandidate,
-      QualType ObjectType, Expr::Classification ObjectClassification,
+      bool PartialOrdering, QualType ObjectType,
+      Expr::Classification ObjectClassification,
       llvm::function_ref<bool(ArrayRef<QualType>)> CheckNonDependent);
 
   /// Deduce template arguments when taking the address of a function
@@ -12421,7 +12423,7 @@ class Sema final : public SemaBase {
   bool isTemplateTemplateParameterAtLeastAsSpecializedAs(
       TemplateParameterList *PParam, TemplateDecl *PArg, TemplateDecl *AArg,
       const DefaultArguments &DefaultArgs, SourceLocation ArgLoc,
-      bool IsDeduced, bool *MatchedPackOnParmToNonPackOnArg);
+      bool PartialOrdering, bool *MatchedPackOnParmToNonPackOnArg);
 
   /// Mark which template parameters are used in a given expression.
   ///
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 31422c213ac249..60fa195221c938 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -3667,6 +3667,7 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
           if (CheckTemplateArgument(
                   Params->getParam(0), Arg, FD, R.getNameLoc(), R.getNameLoc(),
                   0, SugaredChecked, CanonicalChecked, CTAK_Specified,
+                  /*PartialOrdering=*/false,
                   /*MatchedPackOnParmToNonPackOnArg=*/nullptr) ||
               Trap.hasErrorOccurred())
             IsTemplate = false;
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 2cde8131108fbe..a8c3dd05a9a3c5 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -7663,8 +7663,8 @@ void Sema::AddMethodTemplateCandidate(
   ConversionSequenceList Conversions;
   if (TemplateDeductionResult Result = DeduceTemplateArguments(
           MethodTmpl, ExplicitTemplateArgs, Args, Specialization, Info,
-          PartialOverloading, /*AggregateDeductionCandidate=*/false, 
ObjectType,
-          ObjectClassification,
+          PartialOverloading, /*AggregateDeductionCandidate=*/false,
+          /*PartialOrdering=*/false, ObjectType, ObjectClassification,
           [&](ArrayRef<QualType> ParamTypes) {
             return CheckNonDependentConversions(
                 MethodTmpl, ParamTypes, Args, CandidateSet, Conversions,
@@ -7748,6 +7748,7 @@ void Sema::AddTemplateOverloadCandidate(
   if (TemplateDeductionResult Result = DeduceTemplateArguments(
           FunctionTemplate, ExplicitTemplateArgs, Args, Specialization, Info,
           PartialOverloading, AggregateCandidateDeduction,
+          /*PartialOrdering=*/false,
           /*ObjectType=*/QualType(),
           /*ObjectClassification=*/Expr::Classification(),
           [&](ArrayRef<QualType> ParamTypes) {
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 82fd4789956622..94cb4c8e32d703 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -5179,7 +5179,8 @@ bool Sema::CheckTemplateArgument(
     unsigned ArgumentPackIndex,
     SmallVectorImpl<TemplateArgument> &SugaredConverted,
     SmallVectorImpl<TemplateArgument> &CanonicalConverted,
-    CheckTemplateArgumentKind CTAK, bool *MatchedPackOnParmToNonPackOnArg) {
+    CheckTemplateArgumentKind CTAK, bool PartialOrdering,
+    bool *MatchedPackOnParmToNonPackOnArg) {
   // Check template type parameters.
   if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
     return CheckTemplateTypeArgument(TTP, Arg, SugaredConverted,
@@ -5394,8 +5395,7 @@ bool Sema::CheckTemplateArgument(
 
   case TemplateArgument::Template:
   case TemplateArgument::TemplateExpansion:
-    if (CheckTemplateTemplateArgument(TempParm, Params, Arg,
-                                      /*IsDeduced=*/CTAK != CTAK_Specified,
+    if (CheckTemplateTemplateArgument(TempParm, Params, Arg, PartialOrdering,
                                       MatchedPackOnParmToNonPackOnArg))
       return true;
 
@@ -5546,10 +5546,11 @@ bool Sema::CheckTemplateArgumentList(
 
     if (ArgIdx < NumArgs) {
       // Check the template argument we were given.
-      if (CheckTemplateArgument(
-              *Param, NewArgs[ArgIdx], Template, TemplateLoc, RAngleLoc,
-              SugaredArgumentPack.size(), SugaredConverted, CanonicalConverted,
-              CTAK_Specified, MatchedPackOnParmToNonPackOnArg))
+      if (CheckTemplateArgument(*Param, NewArgs[ArgIdx], Template, TemplateLoc,
+                                RAngleLoc, SugaredArgumentPack.size(),
+                                SugaredConverted, CanonicalConverted,
+                                CTAK_Specified, /*PartialOrdering=*/false,
+                                MatchedPackOnParmToNonPackOnArg))
         return true;
 
       CanonicalConverted.back().setIsDefaulted(
@@ -5715,7 +5716,7 @@ bool Sema::CheckTemplateArgumentList(
     // Check the default template argument.
     if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc, RAngleLoc, 0,
                               SugaredConverted, CanonicalConverted,
-                              CTAK_Specified,
+                              CTAK_Specified, /*PartialOrdering=*/false,
                               /*MatchedPackOnParmToNonPackOnArg=*/nullptr))
       return true;
 
@@ -7296,7 +7297,7 @@ static void DiagnoseTemplateParameterListArityMismatch(
 
 bool Sema::CheckTemplateTemplateArgument(
     TemplateTemplateParmDecl *Param, TemplateParameterList *Params,
-    TemplateArgumentLoc &Arg, bool IsDeduced,
+    TemplateArgumentLoc &Arg, bool PartialOrdering,
     bool *MatchedPackOnParmToNonPackOnArg) {
   TemplateName Name = Arg.getArgument().getAsTemplateOrTemplatePattern();
   auto [Template, DefaultArgs] = Name.getTemplateDeclAndDefaultArgs();
@@ -7341,8 +7342,8 @@ bool Sema::CheckTemplateTemplateArgument(
   //   A template-argument matches a template template-parameter P when P
   //   is at least as specialized as the template-argument A.
   if (!isTemplateTemplateParameterAtLeastAsSpecializedAs(
-          Params, Param, Template, DefaultArgs, Arg.getLocation(), IsDeduced,
-          MatchedPackOnParmToNonPackOnArg))
+          Params, Param, Template, DefaultArgs, Arg.getLocation(),
+          PartialOrdering, MatchedPackOnParmToNonPackOnArg))
     return true;
   // P2113
   // C++20[temp.func.order]p2
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp 
b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 925d3cbf9310f7..b4abbf7265da9b 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -2955,7 +2955,7 @@ Sema::getIdentityTemplateArgumentLoc(NamedDecl 
*TemplateParm,
 /// fully-converted template arguments.
 static bool ConvertDeducedTemplateArgument(
     Sema &S, NamedDecl *Param, DeducedTemplateArgument Arg, NamedDecl 
*Template,
-    TemplateDeductionInfo &Info, bool IsDeduced,
+    TemplateDeductionInfo &Info, bool IsDeduced, bool PartialOrdering,
     SmallVectorImpl<TemplateArgument> &SugaredOutput,
     SmallVectorImpl<TemplateArgument> &CanonicalOutput) {
   auto ConvertArg = [&](DeducedTemplateArgument Arg,
@@ -2976,7 +2976,7 @@ static bool ConvertDeducedTemplateArgument(
             ? (Arg.wasDeducedFromArrayBound() ? 
Sema::CTAK_DeducedFromArrayBound
                                               : Sema::CTAK_Deduced)
             : Sema::CTAK_Specified,
-        &MatchedPackOnParmToNonPackOnArg);
+        PartialOrdering, &MatchedPackOnParmToNonPackOnArg);
     if (MatchedPackOnParmToNonPackOnArg)
       Info.setMatchedPackOnParmToNonPackOnArg();
     return Res;
@@ -3062,9 +3062,9 @@ static TemplateDeductionResult 
ConvertDeducedTemplateArguments(
     SmallVectorImpl<DeducedTemplateArgument> &Deduced,
     TemplateDeductionInfo &Info,
     SmallVectorImpl<TemplateArgument> &SugaredBuilder,
-    SmallVectorImpl<TemplateArgument> &CanonicalBuilder,
-    LocalInstantiationScope *CurrentInstantiationScope = nullptr,
-    unsigned NumAlreadyConverted = 0, bool *IsIncomplete = nullptr) {
+    SmallVectorImpl<TemplateArgument> &CanonicalBuilder, bool PartialOrdering,
+    LocalInstantiationScope *CurrentInstantiationScope,
+    unsigned NumAlreadyConverted, bool *IsIncomplete) {
   TemplateParameterList *TemplateParams = Template->getTemplateParameters();
 
   for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
@@ -3107,8 +3107,8 @@ static TemplateDeductionResult 
ConvertDeducedTemplateArguments(
       // We may have deduced this argument, so it still needs to be
       // checked and converted.
       if (ConvertDeducedTemplateArgument(S, Param, Deduced[I], Template, Info,
-                                         IsDeduced, SugaredBuilder,
-                                         CanonicalBuilder)) {
+                                         IsDeduced, PartialOrdering,
+                                         SugaredBuilder, CanonicalBuilder)) {
         Info.Param = makeTemplateParameter(Param);
         // FIXME: These template arguments are temporary. Free them!
         Info.reset(
@@ -3172,10 +3172,11 @@ static TemplateDeductionResult 
ConvertDeducedTemplateArguments(
     }
 
     // Check whether we can actually use the default argument.
-    if (S.CheckTemplateArgument(
-            Param, DefArg, TD, TD->getLocation(), 
TD->getSourceRange().getEnd(),
-            0, SugaredBuilder, CanonicalBuilder, Sema::CTAK_Specified,
-            /*MatchedPackOnParmToNonPackOnArg=*/nullptr)) {
+    if (S.CheckTemplateArgument(Param, DefArg, TD, TD->getLocation(),
+                                TD->getSourceRange().getEnd(), 0,
+                                SugaredBuilder, CanonicalBuilder,
+                                Sema::CTAK_Specified, 
/*PartialOrdering=*/false,
+                                /*MatchedPackOnParmToNonPackOnArg=*/nullptr)) {
       Info.Param = makeTemplateParameter(
                          const_cast<NamedDecl *>(TemplateParams->getParam(I)));
       // FIXME: These template arguments are temporary. Free them!
@@ -3283,7 +3284,9 @@ FinishTemplateArgumentDeduction(
   SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder;
   if (auto Result = ConvertDeducedTemplateArguments(
           S, Partial, IsPartialOrdering, Deduced, Info, SugaredBuilder,
-          CanonicalBuilder);
+          CanonicalBuilder, IsPartialOrdering,
+          /*CurrentInstantiationScope=*/nullptr, /*NumAlreadyConverted=*/0,
+          /*IsIncomplete=*/nullptr);
       Result != TemplateDeductionResult::Success)
     return Result;
 
@@ -3383,10 +3386,10 @@ static TemplateDeductionResult 
FinishTemplateArgumentDeduction(
   //   explicitly specified, template argument deduction fails.
   SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder;
   if (auto Result = ConvertDeducedTemplateArguments(
-          S, Template, /*IsDeduced*/ PartialOrdering, Deduced, Info,
-          SugaredBuilder, CanonicalBuilder,
+          S, Template, /*IsDeduced=*/PartialOrdering, Deduced, Info,
+          SugaredBuilder, CanonicalBuilder, PartialOrdering,
           /*CurrentInstantiationScope=*/nullptr,
-          /*NumAlreadyConverted=*/0U);
+          /*NumAlreadyConverted=*/0U, /*IsIncomplete=*/nullptr);
       Result != TemplateDeductionResult::Success)
     return Result;
 
@@ -3456,7 +3459,9 @@ static TemplateDeductionResult 
FinishTemplateArgumentDeduction(
   SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder;
   if (auto Result = ConvertDeducedTemplateArguments(
           S, TD, /*IsDeduced=*/false, Deduced, Info, SugaredBuilder,
-          CanonicalBuilder);
+          CanonicalBuilder, /*PartialOrdering=*/false,
+          /*CurrentInstantiationScope=*/nullptr, /*NumAlreadyConverted=*/0,
+          /*IsIncomplete=*/nullptr);
       Result != TemplateDeductionResult::Success)
     return Result;
 
@@ -3994,7 +3999,8 @@ TemplateDeductionResult 
Sema::FinishTemplateArgumentDeduction(
     unsigned NumExplicitlySpecified, FunctionDecl *&Specialization,
     TemplateDeductionInfo &Info,
     SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs,
-    bool PartialOverloading, llvm::function_ref<bool()> CheckNonDependent) {
+    bool PartialOverloading, bool PartialOrdering,
+    llvm::function_ref<bool()> CheckNonDependent) {
   // Unevaluated SFINAE context.
   EnterExpressionEvaluationContext Unevaluated(
       *this, Sema::ExpressionEvaluationContext::Unevaluated);
@@ -4017,9 +4023,10 @@ TemplateDeductionResult 
Sema::FinishTemplateArgumentDeduction(
   bool IsIncomplete = false;
   SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder;
   if (auto Result = ConvertDeducedTemplateArguments(
-          *this, FunctionTemplate, /*IsDeduced*/ true, Deduced, Info,
-          SugaredBuilder, CanonicalBuilder, CurrentInstantiationScope,
-          NumExplicitlySpecified, PartialOverloading ? &IsIncomplete : 
nullptr);
+          *this, FunctionTemplate, /*IsDeduced=*/true, Deduced, Info,
+          SugaredBuilder, CanonicalBuilder, PartialOrdering,
+          CurrentInstantiationScope, NumExplicitlySpecified,
+          PartialOverloading ? &IsIncomplete : nullptr);
       Result != TemplateDeductionResult::Success)
     return Result;
 
@@ -4551,7 +4558,8 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
     TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
     FunctionDecl *&Specialization, TemplateDeductionInfo &Info,
     bool PartialOverloading, bool AggregateDeductionCandidate,
-    QualType ObjectType, Expr::Classification ObjectClassification,
+    bool PartialOrdering, QualType ObjectType,
+    Expr::Classification ObjectClassification,
     llvm::function_ref<bool(ArrayRef<QualType>)> CheckNonDependent) {
   if (FunctionTemplate->isInvalidDecl())
     return TemplateDeductionResult::Invalid;
@@ -4766,7 +4774,8 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
   runWithSufficientStackSpace(Info.getLocation(), [&] {
     Result = FinishTemplateArgumentDeduction(
         FunctionTemplate, Deduced, NumExplicitlySpecified, Specialization, 
Info,
-        &OriginalCallArgs, PartialOverloading, [&, CallingCtx]() {
+        &OriginalCallArgs, PartialOverloading, PartialOrdering,
+        [&, CallingCtx]() {
           ContextRAII SavedContext(*this, CallingCtx);
           return CheckNonDependent(ParamTypesForArgChecking);
         });
@@ -4878,9 +4887,10 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
 
   TemplateDeductionResult Result;
   runWithSufficientStackSpace(Info.getLocation(), [&] {
-    Result = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced,
-                                             NumExplicitlySpecified,
-                                             Specialization, Info);
+    Result = FinishTemplateArgumentDeduction(
+        FunctionTemplate, Deduced, NumExplicitlySpecified, Specialization, 
Info,
+        /*OriginalCallArgs=*/nullptr, /*PartialOverloading=*/false,
+        /*PartialOrdering=*/true);
   });
   if (Result != TemplateDeductionResult::Success)
     return Result;
@@ -5060,9 +5070,10 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
   FunctionDecl *ConversionSpecialized = nullptr;
   TemplateDeductionResult Result;
   runWithSufficientStackSpace(Info.getLocation(), [&] {
-    Result = FinishTemplateArgumentDeduction(ConversionTemplate, Deduced, 0,
-                                             ConversionSpecialized, Info,
-                                             &OriginalCallArgs);
+    Result = FinishTemplateArgumentDeduction(
+        ConversionTemplate, Deduced, 0, ConversionSpecialized, Info,
+        &OriginalCallArgs, /*PartialOverloading=*/false,
+        /*PartialOrdering=*/true);
   });
   Specialization = cast_or_null<CXXConversionDecl>(ConversionSpecialized);
   return Result;
@@ -5639,7 +5650,8 @@ static TemplateDeductionResult 
FinishTemplateArgumentDeduction(
   SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder;
   if (auto Result = ConvertDeducedTemplateArguments(
           S, FTD, /*IsDeduced=*/true, Deduced, Info, SugaredBuilder,
-          CanonicalBuilder, /*CurrentInstantiationScope=*/nullptr,
+          CanonicalBuilder, /*PartialOrdering=*/true,
+          /*CurrentInstantiationScope=*/nullptr,
           /*NumAlreadyConverted=*/0, &IsIncomplete);
       Result != TemplateDeductionResult::Success)
     return Result;
@@ -6484,8 +6496,8 @@ bool Sema::isMoreSpecializedThanPrimary(
 
 bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
     TemplateParameterList *P, TemplateDecl *PArg, TemplateDecl *AArg,
-    const DefaultArguments &DefaultArgs, SourceLocation ArgLoc, bool IsDeduced,
-    bool *MatchedPackOnParmToNonPackOnArg) {
+    const DefaultArguments &DefaultArgs, SourceLocation ArgLoc,
+    bool PartialOrdering, bool *MatchedPackOnParmToNonPackOnArg) {
   // C++1z [temp.arg.template]p4: (DR 150)
   //   A template template-parameter P is at least as specialized as a
   //   template template-argument A if, given the following rewrite to two
@@ -6564,7 +6576,7 @@ bool 
Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
   switch (::DeduceTemplateArguments(
       *this, A, AArgs, PArgs, Info, Deduced,
       /*NumberOfArgumentsMustMatch=*/false, /*PartialOrdering=*/true,
-      IsDeduced ? PackFold::ArgumentToParameter : PackFold::Both,
+      PartialOrdering ? PackFold::ArgumentToParameter : PackFold::Both,
       /*HasDeducedAnyParam=*/nullptr)) {
   case clang::TemplateDeductionResult::Success:
     if (MatchedPackOnParmToNonPackOnArg &&
diff --git a/clang/test/SemaTemplate/cwg2398.cpp 
b/clang/test/SemaTemplate/cwg2398.cpp
index b161b5a542b38f..a7ff06748068d5 100644
--- a/clang/test/SemaTemplate/cwg2398.cpp
+++ b/clang/test/SemaTemplate/cwg2398.cpp
@@ -405,6 +405,40 @@ namespace packs {
   } // namespace t4
 } // namespace packs
 
+namespace fun_tmpl_call {
+  namespace t1 {
+    template <template <class> class TT> void f(TT<int>) {};
+    // old-note@-1 {{has different template parameters}}
+    template <class...> struct A {};
+    void test() { f(A<int>()); }
+    // old-error@-1 {{no matching function for call to 'f'}}
+  } // namespace t1
+  namespace t2 {
+    template <template <class> class TT> void f(TT<int>) = delete;
+    // new-note@-1 {{candidate function}}
+    template <template <class...> class TT> void f(TT<int>) {}
+    // new-note@-1 {{candidate function}}
+
+    template <class...> struct A {};
+    void test() { f(A<int>()); }
+    // new-error@-1 {{call to deleted function 'f'}}
+  } // namespace t2
+  namespace t3 {
+    template <template <class> class TT> void f(TT<int>) {}
+    template <template <class...> class TT> void f(TT<int>) = delete;
+
+    template <class> struct A {};
+    void test() { f(A<int>()); }
+  } // namespace t3
+  namespace t4 {
+    template <template <class, class...> class TT, class T1, class... T2s>
+    void f(TT<T1, T2s...>) {}
+
+    template <class> struct A {};
+    void test() { f(A<int>()); }
+  } // namespace t4
+} // namespace fun_tmpl_packs
+
 namespace partial {
   namespace t1 {
     template<template<class... T1s> class TT1> struct A {};

_______________________________________________
llvm-branch-commits mailing list
llvm-branch-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to