================
@@ -5054,95 +5089,128 @@ bool 
TreeTransform<Derived>::TransformTemplateArguments(
     }
 
     if (In.getArgument().isPackExpansion()) {
-      // We have a pack expansion, for which we will be substituting into
-      // the pattern.
-      SourceLocation Ellipsis;
-      UnsignedOrNone OrigNumExpansions = std::nullopt;
-      TemplateArgumentLoc Pattern
-        = getSema().getTemplateArgumentPackExpansionPattern(
-              In, Ellipsis, OrigNumExpansions);
-
-      SmallVector<UnexpandedParameterPack, 2> Unexpanded;
-      getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded);
-      assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
-
-      // Determine whether the set of unexpanded parameter packs can and should
-      // be expanded.
-      bool Expand = true;
-      bool RetainExpansion = false;
-      UnsignedOrNone NumExpansions = OrigNumExpansions;
-      if (getDerived().TryExpandParameterPacks(Ellipsis,
-                                               Pattern.getSourceRange(),
-                                               Unexpanded,
-                                               Expand,
-                                               RetainExpansion,
-                                               NumExpansions))
+      if (ExpandTemplateArgument(In, Outputs, Uneval, true))
         return true;
+      continue;
+    }
 
-      if (!Expand) {
-        // The transform has determined that we should perform a simple
-        // transformation on the pack expansion, producing another pack
-        // expansion.
-        TemplateArgumentLoc OutPattern;
-        Sema::ArgPackSubstIndexRAII SubstIndex(getSema(), std::nullopt);
-        if (getDerived().TransformTemplateArgument(Pattern, OutPattern, 
Uneval))
-          return true;
+    // The simple case:
+    if (getDerived().TransformTemplateArgument(In, Out, Uneval))
+      return true;
 
-        Out = getDerived().RebuildPackExpansion(OutPattern, Ellipsis,
-                                                NumExpansions);
-        if (Out.getArgument().isNull())
-          return true;
+    Outputs.addArgument(Out);
+  }
 
-        Outputs.addArgument(Out);
-        continue;
-      }
+  return false;
+}
 
-      // The transform has determined that we should perform an elementwise
-      // expansion of the pattern. Do so.
-      for (unsigned I = 0; I != *NumExpansions; ++I) {
-        Sema::ArgPackSubstIndexRAII SubstIndex(getSema(), I);
+template <typename Derived>
+bool TreeTransform<Derived>::ExpandTemplateArgument(
+    TemplateArgumentLoc In, TemplateArgumentListInfo &Outputs, bool Uneval,
+    bool TryExpandingSubstPacks) {
+  assert(In.getArgument().isPackExpansion());
+  // We have a pack expansion, for which we will be substituting into the
+  // pattern.
+  SourceLocation Ellipsis;
+  UnsignedOrNone OrigNumExpansions = std::nullopt;
+  TemplateArgumentLoc Pattern =
+      getSema().getTemplateArgumentPackExpansionPattern(In, Ellipsis,
+                                                        OrigNumExpansions);
 
-        if (getDerived().TransformTemplateArgument(Pattern, Out, Uneval))
-          return true;
+  SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+  getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded);
+  if (!TryExpandingSubstPacks) {
+    // Only do something if there is an opportunity for late expansion.
+    bool SawPackTypes = llvm::any_of(Unexpanded, [](UnexpandedParameterPack P) 
{
+      return P.first.dyn_cast<const SubstBuiltinTemplatePackType *>();
+    });
+    if (!SawPackTypes) {
+      Outputs.addArgument(In);
+      return false;
+    }
+  }
+  assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
 
-        if (Out.getArgument().containsUnexpandedParameterPack()) {
-          Out = getDerived().RebuildPackExpansion(Out, Ellipsis,
-                                                  OrigNumExpansions);
-          if (Out.getArgument().isNull())
-            return true;
-        }
+  // Determine whether the set of unexpanded parameter packs can and should
+  // be expanded.
+  bool Expand = true;
+  bool RetainExpansion = false;
+  UnsignedOrNone NumExpansions = OrigNumExpansions;
+  if (getDerived().TryExpandParameterPacks(Ellipsis, Pattern.getSourceRange(),
+                                           Unexpanded, Expand, RetainExpansion,
+                                           NumExpansions))
+    return true;
 
-        Outputs.addArgument(Out);
-      }
+  TemplateArgumentLoc Out;
+  if (!Expand) {
+    // No opportunity for late expansion, return as is.
+    if (!TryExpandingSubstPacks) {
+      Outputs.addArgument(In);
+      return false;
+    }
+    // The transform has determined that we should perform a simple
+    // transformation on the pack expansion, producing another pack
+    // expansion.
+    TemplateArgumentLoc OutPattern;
+    std::optional<Sema::ArgPackSubstIndexRAII> SubstIndex(
+        std::in_place, getSema(), std::nullopt);
+    if (getDerived().TransformTemplateArgument(Pattern, OutPattern, Uneval))
+      return true;
 
-      // If we're supposed to retain a pack expansion, do so by temporarily
-      // forgetting the partially-substituted parameter pack.
-      if (RetainExpansion) {
-        ForgetPartiallySubstitutedPackRAII Forget(getDerived());
+    Out =
+        getDerived().RebuildPackExpansion(OutPattern, Ellipsis, NumExpansions);
+    if (Out.getArgument().isNull())
+      return true;
+    SubstIndex.reset();
+
+    // Some packs only know their lengths after substitution. We might be able
+    // to expand those here.
+    if (TryExpandingSubstPacks &&
+        OutPattern.getArgument().containsUnexpandedParameterPack()) {
----------------
ilya-biryukov wrote:

Consider  the difference between a template parameter pack and a new 
substituted pack:
```cpp
template <class ...T>
struct Foo {
  using type1 = tuple<T...>;
  using type2 = tuple<builtin_dedup_pack<T...>...>;
}
```

When substituting (e.g. to `Foo<int, int, double>`) into `type1`, we know the 
number of template arguments we will produce **before** we substitute into 
`T...` as we know the argument pack for `T`. However, to compute the number of 
template arguments we will produce for `builtin_dedup_pack<T...>...` in 
`type2`, we first need to do the actual substitution and compute the results 
(size of the output depends on the computations the builtin does).

The approach I've taken is to first substitute and produce a **single** 
template argument that directly contains the argument pack (we also have those 
in some cases for templates, see the two descendant of the added 
`SubstPackType` for both the new and the old types). Then we do a second pass 
will transform that single template argument produced on the first step into a 
list of template arguments.
The code needed for both branches is very similar, and in fact most of the time 
we don't have those builtins and only a single branch runs anyway, hence 
there's a shared function that recurses into itself no more than once (hence 
the added parameter).


Let me know if this makes sense.

https://github.com/llvm/llvm-project/pull/106730
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to