================
@@ -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()) {
----------------
zyn0217 wrote:

I'm thinking if we shall move the second-pass-expansion-transform out of 
TransformTemplateArguments. It seemed that so far only TST that model a 
"synthesized" pack type can benefit from the two level transform, and 
separating that explicitly makes the structure clearer to me.

Maybe we could move it to just after the first transform of template arguments 
inside TST, or possibly override the rebuild process for TST itself? 
Essentially, we're now just reusing TST to represent the novel "synthesized" 
packs (I haven't come up with a better name yet), and ideally we want to extend 
it / probably invent a new type node to support other pack forms outside of the 
template context, so not baking it into TemplateArgument transform makes some 
sense to me.

That said, I'm not sure what direction we want to take here, so CC @cor3ntin 
@erichkeane @mizvekov for ideas!

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