[clang] [Sema] Preserve ContainsUnexpandedParameterPack in TransformLambdaExpr (PR #86265)
Younan Zhang via cfe-commits
cfe-commits at lists.llvm.org
Mon Aug 5 05:31:25 PDT 2024
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
More information about the cfe-commits
mailing list