================
@@ -1394,7 +1395,22 @@ namespace {
                                  SourceRange PatternRange,
                                  ArrayRef<UnexpandedParameterPack> Unexpanded,
                                  bool &ShouldExpand, bool &RetainExpansion,
-                                 std::optional<unsigned> &NumExpansions) {
+                                 std::optional<unsigned> &NumExpansions,
+                                 bool ForConstraints = false) {
+      if (ForConstraints) {
+        LambdaScopeInfo *LSI = getSema().getCurLambda();
+        if (LSI) {
+          MultiLevelTemplateArgumentList MLTAL =
+              getSema().getTemplateInstantiationArgs(
+                  LSI->CallOperator, /*DC=*/nullptr, /*Final=*/false,
+                  /*Innermost=*/std::nullopt, /*RelativeToPrimary=*/true,
+                  /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true);
+          return getSema().CheckParameterPacksForExpansion(
+              EllipsisLoc, PatternRange, Unexpanded, MLTAL, ShouldExpand,
+              RetainExpansion, NumExpansions);
+        }
----------------
zyn0217 wrote:

This is the most convoluted part in this patch. Basically, this targets for a 
situation where unexpanded packs appear in a trailing constraint. On the basis 
of our evaluation strategy, we need the complete template arguments, (which are 
typically relative to the primary template, as opposed to other instantiation 
algorithm where we usually need the template arguments relative to the parent 
specializations.) whereas we don't always have them at the time expanding a 
CXXFoldExpr.

For example, suppose we have
```cpp
template <class = void> void foo() {
 []<class... Is>() {
    ([]()
       requires (!C<Is>)
     {}(),
     ...);
  }.template operator()<char, int, float>();
}
``` 

We would only have one level template arguments, which is `<char, int, float>` 
when the inner fold expression gets expanded. Since we always preserve the 
constraint expressions until we evaluate them, we would thereafter have the 
inner lambda being unexpanded, which is wrong because, later we need to 
evaluate an expanded constraint when forming CallExprs.

So, one way is to teach the transformation to handle the constraints separately:
If we have only a constraint that contains unexpanded packs, we need to 
*expand* the expression because we don't actually need to use the constraint 
immediately. (in other words, the untransformed constraint shouldn't impact the 
expansion)

And vice versa: if we have combined constraints and other unexpanded packs, we 
just do the usual: we could hold off on the expansion until we hit the point 
where only unexpanded constraints are left, which boils down to the above case.

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

Reply via email to