[libcxx-commits] [libcxx] 9abb97f - [clang] Handle template argument conversions for non-pack param to pack argument (#110963)

via libcxx-commits libcxx-commits at lists.llvm.org
Thu Oct 3 11:18:42 PDT 2024


Author: Matheus Izvekov
Date: 2024-10-03T15:18:37-03:00
New Revision: 9abb97f9663a27fe5b8e346ed557b3435aa9ec2f

URL: https://github.com/llvm/llvm-project/commit/9abb97f9663a27fe5b8e346ed557b3435aa9ec2f
DIFF: https://github.com/llvm/llvm-project/commit/9abb97f9663a27fe5b8e346ed557b3435aa9ec2f.diff

LOG: [clang] Handle template argument conversions for non-pack param to pack argument (#110963)

This fixes a regression introduced in #96023, reported in
https://github.com/llvm/llvm-project/issues/110231#issuecomment-2389131854

Added: 
    

Modified: 
    clang/lib/Sema/SemaTemplate.cpp
    clang/lib/Sema/SemaTemplateDeduction.cpp
    clang/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp
    clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp
    clang/test/SemaTemplate/cwg2398.cpp
    clang/test/SemaTemplate/temp_arg_template_p0522.cpp
    libcxx/test/libcxx/type_traits/is_specialization.verify.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 226c1172a059d4..eeaa1ebd7ba83a 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -5579,9 +5579,6 @@ bool Sema::CheckTemplateArgumentList(
         return true;
       }
 
-      // We're now done with this argument.
-      ++ArgIdx;
-
       if ((*Param)->isTemplateParameterPack()) {
         // The template parameter was a template parameter pack, so take the
         // deduced argument and place it on the argument pack. Note that we
@@ -5592,8 +5589,19 @@ bool Sema::CheckTemplateArgumentList(
       } else {
         // Move to the next template parameter.
         ++Param;
+        if (PartialOrderingTTP && PackExpansionIntoNonPack) {
+          // Keep converting the pattern in the argument against
+          // subsequent parameters. The argument is converted
+          // in place and will be added back when we are done.
+          SugaredConverted.pop_back();
+          CanonicalConverted.pop_back();
+          continue;
+        }
       }
 
+      // We're now done with this argument.
+      ++ArgIdx;
+
       // If we just saw a pack expansion into a non-pack, then directly convert
       // the remaining arguments, because we don't know what parameters they'll
       // match up with.
@@ -5727,15 +5735,10 @@ bool Sema::CheckTemplateArgumentList(
   // pack expansions; they might be empty. This can happen even if
   // PartialTemplateArgs is false (the list of arguments is complete but
   // still dependent).
-  if (PartialOrderingTTP ||
-      (CurrentInstantiationScope &&
-       CurrentInstantiationScope->getPartiallySubstitutedPack())) {
-    while (ArgIdx < NumArgs &&
-           NewArgs[ArgIdx].getArgument().isPackExpansion()) {
-      const TemplateArgument &Arg = NewArgs[ArgIdx++].getArgument();
-      SugaredConverted.push_back(Arg);
-      CanonicalConverted.push_back(Context.getCanonicalTemplateArgument(Arg));
-    }
+  while (ArgIdx < NumArgs && NewArgs[ArgIdx].getArgument().isPackExpansion()) {
+    const TemplateArgument &Arg = NewArgs[ArgIdx++].getArgument();
+    SugaredConverted.push_back(Arg);
+    CanonicalConverted.push_back(Context.getCanonicalTemplateArgument(Arg));
   }
 
   // If we have any leftover arguments, then there were too many arguments.

diff  --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 03ff8145e3b4ac..ce3317db5a8202 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3377,35 +3377,40 @@ static TemplateDeductionResult FinishTemplateArgumentDeduction(
     return Result;
 
   // Check that we produced the correct argument list.
-  TemplateParameterList *TemplateParams = Template->getTemplateParameters();
-  auto isSame = [&](unsigned I, const TemplateArgument &P,
-                    const TemplateArgument &A) {
-    if (isSameTemplateArg(S.Context, P, A, PartialOrdering,
-                          /*PackExpansionMatchesPack=*/true))
-      return true;
-    Info.Param = makeTemplateParameter(TemplateParams->getParam(I));
+  for (ArrayRef<TemplateArgument> Ps = TemplateArgs, As = CanonicalBuilder;
+       !Ps.empty() && !As.empty();
+       /**/) {
+    TemplateArgument P = Ps.front(), A = As.front();
+    if (P.getKind() == TemplateArgument::Pack) {
+      assert(Ps.size() == 1 && "Pack not last element?");
+      Ps = P.getPackAsArray();
+      continue;
+    }
+    if (A.getKind() == TemplateArgument::Pack) {
+      assert(As.size() == 1 && "Pack not last element?");
+      As = A.getPackAsArray();
+      continue;
+    }
+
+    if (P.isPackExpansion())
+      P = P.getPackExpansionPattern();
+    else
+      Ps = Ps.drop_front();
+    if (A.isPackExpansion())
+      A = A.getPackExpansionPattern();
+    else
+      As = As.drop_front();
+
+    if (isSameTemplateArg(S.Context, P, A, PartialOrdering))
+      continue;
+    unsigned I = As.end() == CanonicalBuilder.end()
+                     ? As.begin() - CanonicalBuilder.begin()
+                     : CanonicalBuilder.size() - 1;
+    Info.Param =
+        makeTemplateParameter(Template->getTemplateParameters()->getParam(I));
     Info.FirstArg = P;
     Info.SecondArg = A;
-    return false;
-  };
-  for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) {
-    const TemplateArgument &P = TemplateArgs[I];
-    if (P.isPackExpansion()) {
-      assert(I == TemplateArgs.size() - 1);
-      for (/**/; I != E; ++I) {
-        const TemplateArgument &A = CanonicalBuilder[I];
-        if (A.getKind() == TemplateArgument::Pack) {
-          for (const TemplateArgument &Ai : A.getPackAsArray())
-            if (!isSame(I, P, Ai))
-              return TemplateDeductionResult::NonDeducedMismatch;
-        } else if (!isSame(I, P, A)) {
-          return TemplateDeductionResult::NonDeducedMismatch;
-        }
-      }
-      break;
-    }
-    if (!isSame(I, P, CanonicalBuilder[I]))
-      return TemplateDeductionResult::NonDeducedMismatch;
+    return TemplateDeductionResult::NonDeducedMismatch;
   }
 
   if (!PartialOrdering) {

diff  --git a/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp b/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp
index 1bbbd1d3429ddd..ce27e6aa83c3b9 100644
--- a/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp
+++ b/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp
@@ -18,7 +18,7 @@ eval<D<int, 17>> eD; // expected-error{{implicit instantiation of undefined temp
 eval<E<int, float>> eE; // expected-error{{implicit instantiation of undefined template 'eval<E<int, float>>}}
 
 template<
-  template <int ...N> // expected-error{{deduced non-type template argument does not have the same type as the corresponding template parameter ('int' vs 'long')}}
+  template <int ...N> // expected-error{{deduced non-type template argument does not have the same type as the corresponding template parameter ('long' vs 'int')}}
   class TT // expected-note {{previous template template parameter is here}}
 > struct X0 { };
 
@@ -31,7 +31,7 @@ X0<X0b> inst_x0b;
 X0<X0c> inst_x0c; // expected-note{{template template argument has 
diff erent template parameters than its corresponding template template parameter}}
 
 template<typename T,
-         template <T ...N> // expected-error{{deduced non-type template argument does not have the same type as the corresponding template parameter ('short' vs 'long')}}
+         template <T ...N> // expected-error{{deduced non-type template argument does not have the same type as the corresponding template parameter ('long' vs 'short')}}
          class TT // expected-note {{previous template template parameter is here}}
 > struct X1 { };
 template<int I, int J, int ...Rest> struct X1a;

diff  --git a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp
index 51df1e0b14541b..fbda7cbe696bb0 100644
--- a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp
+++ b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp
@@ -29,10 +29,14 @@ namespace PackExpansionNotAtEnd {
                                                 >::value? 1 : -1];
 
   template<typename ... Types> struct UselessPartialSpec;
+  // expected-note at -1 {{template is declared here}}
 
+  // FIXME: We should simply disallow a pack expansion which is not at
+  // the end of the partial spec template argument list.
   template<typename ... Types, // expected-note{{non-deducible template parameter 'Types'}}
            typename Tail> // expected-note{{non-deducible template parameter 'Tail'}}
   struct UselessPartialSpec<Types..., Tail>; // expected-error{{class template partial specialization contains template parameters that cannot be deduced; this partial specialization will never be used}}
+  // expected-error at -1 {{is not more specialized than the primary template}}
 }
 
 // When a pack expansion occurs within a template argument list, the entire

diff  --git a/clang/test/SemaTemplate/cwg2398.cpp b/clang/test/SemaTemplate/cwg2398.cpp
index b9e9e9f0c97f26..1b55af782fcb7c 100644
--- a/clang/test/SemaTemplate/cwg2398.cpp
+++ b/clang/test/SemaTemplate/cwg2398.cpp
@@ -541,3 +541,9 @@ namespace regression2 {
   template <typename, int> struct Matrix;
   template struct D<Matrix<double, 3>>;
 } // namespace regression2
+
+namespace regression3 {
+  template <template <auto...> class TT> struct A {};
+  template <auto, int> struct B;
+  template struct A<B>;
+} // namespace regression3

diff  --git a/clang/test/SemaTemplate/temp_arg_template_p0522.cpp b/clang/test/SemaTemplate/temp_arg_template_p0522.cpp
index d40577d5270468..441b9e5af9d3d7 100644
--- a/clang/test/SemaTemplate/temp_arg_template_p0522.cpp
+++ b/clang/test/SemaTemplate/temp_arg_template_p0522.cpp
@@ -21,7 +21,7 @@ template<int, int> struct ii;
 template<int...> struct Pi;
 template<int, int, int...> struct iiPi;
 
-template<int, typename = int> struct iDt; // #iDt
+template<int, typename = int> struct iDt;
 template<int, typename> struct it; // #it
 
 template<typename T, T v> struct t0;
@@ -50,9 +50,9 @@ namespace IntPackParam {
   using ok_compat = Pt<TPi<i>, TPi<iDi>, TPi<ii>, TPi<iiPi>>;
   using err1 = TPi<t0>; // expected-error@#TPi {{template argument for template type parameter must be a type}}
                         // expected-note at -1 {{
diff erent template parameters}}
-  using err2 = TPi<iDt>; // expected-error@#iDt {{could not match 'type-parameter-0-1' against}}
+  using err2 = TPi<iDt>; // expected-error@#TPi {{template argument for template type parameter must be a type}}
                          // expected-note at -1 {{
diff erent template parameters}}
-  using err3 = TPi<it>; // expected-error@#it {{could not match 'type-parameter-0-1' against}}
+  using err3 = TPi<it>; // expected-error@#TPi {{template argument for template type parameter must be a type}}
                         // expected-note at -1 {{
diff erent template parameters}}
 }
 

diff  --git a/libcxx/test/libcxx/type_traits/is_specialization.verify.cpp b/libcxx/test/libcxx/type_traits/is_specialization.verify.cpp
index 3593c2e095db91..a2ea8efcbe5de6 100644
--- a/libcxx/test/libcxx/type_traits/is_specialization.verify.cpp
+++ b/libcxx/test/libcxx/type_traits/is_specialization.verify.cpp
@@ -17,5 +17,5 @@
 #include <array>
 #include <utility>
 
-// expected-error-re@*:* {{{{could not match _Size against 'type-parameter-0-0'|
diff erent template parameters}}}}
+// expected-error-re@*:* {{{{must be an expression|
diff erent template parameters}}}}
 static_assert(!std::__is_specialization_v<std::pair<int, std::size_t>, std::array>);


        


More information about the libcxx-commits mailing list