[clang] [Clang] Transform lambda's constraints when instantiating parameter mapping (PR #195995)

Younan Zhang via cfe-commits cfe-commits at lists.llvm.org
Thu May 7 20:07:03 PDT 2026


================
@@ -1876,11 +1901,25 @@ namespace {
                               TemplateParameterList *OrigTPL)  {
       if (!OrigTPL || !OrigTPL->size()) return OrigTPL;
 
+      std::optional<MultiLevelTemplateArgumentList> OldMLTAL;
+      // We need to preserve the lambda depth in parameter mapping.
+      // Otherwise the template argument deduction would fail, if we reduced the
+      // depth too early.
+      if (SemaRef.inParameterMappingSubstitution() &&
+          getDepthAndIndex(OrigTPL->getParam(0)).first >=
+              TemplateArgs.getNumSubstitutedLevels())
+        OldMLTAL = ForgetSubstitution();
----------------
zyn0217 wrote:

> Also, I don't see how the level check is necessary. 

@mizvekov

The fact is that we will transform the lambda expression in both building and substitution of parameter mapping.

Say we have

```cpp
template<auto Pred, typename... Ts>
concept PredicateFor_bad = pass_a_concept_inside_a_lambda<[]<typename... Xs>
                                          requires(__is_same(decltype(Pred.template operator()<Xs>()), bool) and ...)
                                      {},
                                      Ts...>;
```

When building, we only have outer template arguments `<Pred, <Ts...>>`, and since the transform of parameter list will reduce the depth of <Xs...> anyway if only partial template arguments are provided, depth of <Xs> will be converted to 0.

And in the second transform where we started to substitute real template arguments into parameter mapping (i.e. when we have `<Pred=lambda, Ts=<int, int, int>>`), the depth of `Xs` is reduced before deduction happens. This results in a -1 depth during argument deduction and thus we won't have a correct template argument list when checking the inner constraint.

Note that we didn't transform the lambda expression in the second transfrom, because the lambda was seen as non-dependent. I do want the lambda to have a second transform, because otherwise we don't have a way to get substituted `Pred` in constraint evaluation. (`Pred` is normalized and we have to evaluate the lambda's inner constraint during parameter mapping substitution, when we dont have any proper template arguments at that moment, which is an egg-and-chicken problem though)

https://github.com/llvm/llvm-project/pull/195995


More information about the cfe-commits mailing list