zyn0217 wrote:

> I might be stupid but i still do not get why fold expressions are special, 
> they should not be.

Sorry I was inaccurate suggesting fold expressions are special, it's actually 
*constraints involving pack expansions* who are special. (I admit inventing 
another `collectUnexpandedParameterPacks` overload for `CXXFoldExpr` is odd, 
probably insufficent for the solution because we seem to have more problems - 
as I observed a similar issue from your first example as well - regarding pack 
expansion in terms of the constraints on lambdas.)

> 
> ```cpp
> void f(auto...);
> template <class = void> void foo() {
> []<class... Is>() {
>    f([]() requires (!C<Is>) {}()...);
>  }.template operator()<char, int, float>();
>}
> ```

This is awkward: no compiler currently compiles it. 
(https://gcc.godbolt.org/z/rce3rh7jK) And spuriously, both gcc and clang think 
that there are no unexpanded parameter packs for expansion. 

Regardless of whether this is conforming, the diagnostic here is simple to 
explain: we didn't preserve the `ContainsUnexpandedParameterPack` flag while 
transforming the LambdaExpr, so as an intuitive solution, we could just retain 
the flag from `TransformLambdaExpr`:

(Though I didn't add the following to the patch yet, it doesn't solve the 
problem and instead would cause a crash)

```cpp
Expr *TrailingRequires = E->getCallOperator()->getTrailingRequiresClause();
  if (TrailingRequires)
    LSI->ContainsUnexpandedParameterPack |=
        TrailingRequires->containsUnexpandedParameterPack();
```

We still fail to evaluate the constraint because it ends up being dependent 
even with proper template arguments. This is because the expression is not 
expanded anywhere before evaluating the constraint, which is one step when we 
forming up a CallExpr.

The situation could be slightly different (or rather, better?) if a fold 
expression gets involved. We would still have a chance to expand the fold 
expression into an expanded but unsubstituted state. So we can make them into 
the constraint evaluation and substitute arguments there, and get a correct 
result. So this is why it's convoluted: we probably miss out on some passes for 
constraint packs: Maybe we need to expand them somewhere before evaluation, but 
I'm not completely clear.

> ```cpp
> f<[]() requires (!C<Is>) {}()...>();
> //
> f({+[]() requires (!C<Is>) {}()...});
> // I am truly sorry.
> [ ...fs = +[]() requires (!C<Is>) {}()]() {
>  (fs(),...);
> }
> ```

(I promise I won't forget them but let's consider them when we get around to 
the constraints in the next patch. :)


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