[clang] e8f198d - Fix pack deduction to only deduce the arity of packs that are actually

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Wed Jan 15 16:21:18 PST 2020


Author: Richard Smith
Date: 2020-01-15T16:21:08-08:00
New Revision: e8f198dd9e9dabed8d50276465906e7c8827cada

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

LOG: Fix pack deduction to only deduce the arity of packs that are actually
expanded by the deduced pack.

We recently started also deducing the arity of separately-expanded packs
that are merely mentioned within the pack in question, which is
incorrect.

Added: 
    

Modified: 
    clang/lib/Sema/SemaTemplateDeduction.cpp
    clang/test/SemaTemplate/deduction.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 1b9f1b2144d1..048a50a741e4 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -724,38 +724,48 @@ class PackDeductionScope {
     // Compute the set of template parameter indices that correspond to
     // parameter packs expanded by the pack expansion.
     llvm::SmallBitVector SawIndices(TemplateParams->size());
+    llvm::SmallVector<TemplateArgument, 4> ExtraDeductions;
 
     auto AddPack = [&](unsigned Index) {
       if (SawIndices[Index])
         return;
       SawIndices[Index] = true;
       addPack(Index);
+
+      // Deducing a parameter pack that is a pack expansion also constrains the
+      // packs appearing in that parameter to have the same deduced arity. Also,
+      // in C++17 onwards, deducing a non-type template parameter deduces its
+      // type, so we need to collect the pending deduced values for those packs.
+      if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(
+              TemplateParams->getParam(Index))) {
+        if (auto *Expansion = dyn_cast<PackExpansionType>(NTTP->getType()))
+          ExtraDeductions.push_back(Expansion->getPattern());
+      }
+      // FIXME: Also collect the unexpanded packs in any type and template
+      // parameter packs that are pack expansions.
     };
 
-    // First look for unexpanded packs in the pattern.
-    SmallVector<UnexpandedParameterPack, 2> Unexpanded;
-    S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
-    for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
-      unsigned Depth, Index;
-      std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]);
-      if (Depth == Info.getDeducedDepth())
-        AddPack(Index);
-    }
+    auto Collect = [&](TemplateArgument Pattern) {
+      SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+      S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
+      for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
+        unsigned Depth, Index;
+        std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]);
+        if (Depth == Info.getDeducedDepth())
+          AddPack(Index);
+      }
+    };
+
+    // Look for unexpanded packs in the pattern.
+    Collect(Pattern);
     assert(!Packs.empty() && "Pack expansion without unexpanded packs?");
 
     unsigned NumNamedPacks = Packs.size();
 
-    // We can also have deduced template parameters that do not actually
-    // appear in the pattern, but can be deduced by it (the type of a non-type
-    // template parameter pack, in particular). These won't have prevented us
-    // from partially expanding the pack.
-    llvm::SmallBitVector Used(TemplateParams->size());
-    MarkUsedTemplateParameters(S.Context, Pattern, /*OnlyDeduced*/true,
-                               Info.getDeducedDepth(), Used);
-    for (int Index = Used.find_first(); Index != -1;
-         Index = Used.find_next(Index))
-      if (TemplateParams->getParam(Index)->isParameterPack())
-        AddPack(Index);
+    // Also look for unexpanded packs that are indirectly deduced by deducing
+    // the sizes of the packs in this pattern.
+    while (!ExtraDeductions.empty())
+      Collect(ExtraDeductions.pop_back_val());
 
     return NumNamedPacks;
   }

diff  --git a/clang/test/SemaTemplate/deduction.cpp b/clang/test/SemaTemplate/deduction.cpp
index 1f1c30a8b4ab..7268912dd6c5 100644
--- a/clang/test/SemaTemplate/deduction.cpp
+++ b/clang/test/SemaTemplate/deduction.cpp
@@ -546,3 +546,21 @@ namespace designators {
 
   static_assert(f({.a = 1, .b = 2}) == 3, ""); // expected-error {{no matching function}}
 }
+
+namespace nested_packs {
+  template<typename ...T, typename ...U> void f(T (*...f)(U...)); // expected-note {{deduced packs of 
diff erent lengths for parameter 'U' (<> vs. <int>)}}
+  void g() { f(g); f(g, g); f(g, g, g); }
+  void h(int) { f(h); f(h, h); f(h, h, h); }
+  void i() { f(g, h); } // expected-error {{no matching function}}
+
+#if __cplusplus >= 201703L
+  template<auto ...A> struct Q {};
+  template<typename ...T, T ...A, T ...B> void q(Q<A...>, Q<B...>); // #q
+  void qt(Q<> q0, Q<1, 2> qii, Q<1, 2, 3> qiii) {
+    q(q0, q0);
+    q(qii, qii);
+    q(qii, qiii); // expected-error {{no match}} expected-note@#q {{deduced packs of 
diff erent lengths for parameter 'T' (<int, int> vs. <int, int, int>)}}
+    q(q0, qiii); // expected-error {{no match}} expected-note@#q {{deduced packs of 
diff erent lengths for parameter 'T' (<> vs. <int, int, int>)}}
+  }
+#endif
+}


        


More information about the cfe-commits mailing list