diff options
author | Younan Zhang <zyn7109@gmail.com> | 2024-02-23 09:36:32 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-23 09:36:32 +0800 |
commit | 19e518d2623c0e87a87ebf30405e74448bd1ee70 (patch) | |
tree | 88e9793f389bb04a56b30fb65ac845fe55161901 | |
parent | 590c968e7943e51bb00ff75d312435f24d983b2a (diff) | |
download | llvm-19e518d2623c0e87a87ebf30405e74448bd1ee70.zip llvm-19e518d2623c0e87a87ebf30405e74448bd1ee70.tar.gz llvm-19e518d2623c0e87a87ebf30405e74448bd1ee70.tar.bz2 |
[Clang][Parser] Have the depth of the abbreviated generic lambdas inside a requires clause differ from the surrounding generic lambda (#80656)
A one-line fix, again : )
This fixes https://github.com/llvm/llvm-project/issues/78524 and the
similar example at
https://github.com/llvm/llvm-project/issues/78524#issuecomment-1899886951.
We previously increased the template depth by one after parsing the
attaching requires-clause on a lambda expression. This led to a problem
where the 'auto' parameters of nested abbreviated generic lambdas,
inside of a requires-expression, had the same depth as the template
parameters of the surrounding lambda. Consequently, during the
concept-checking stage, we ended up substituting these parameters with
the wrong template arguments because they were at different levels.
-rw-r--r-- | clang/docs/ReleaseNotes.rst | 4 | ||||
-rw-r--r-- | clang/lib/Parse/ParseExprCXX.cpp | 11 | ||||
-rw-r--r-- | clang/test/Parser/cxx-concepts-requires-clause.cpp | 27 |
3 files changed, 41 insertions, 1 deletions
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 19cc5b7..529dd78 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -277,6 +277,10 @@ Bug Fixes to C++ Support (`#82258 <https://github.com/llvm/llvm-project/issues/82258>`_) - Correctly immediate-escalate lambda conversion functions. (`#82258 <https://github.com/llvm/llvm-project/issues/82258>`_) +- Fixed an issue where template parameters of a nested abbreviated generic lambda within + a requires-clause lie at the same depth as those of the surrounding lambda. This, + in turn, results in the wrong template argument substitution during constraint checking. + (`#78524 <https://github.com/llvm/llvm-project/issues/78524>`_) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index fd262ff..22ee60a 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1385,6 +1385,16 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( Diag(RAngleLoc, diag::err_lambda_template_parameter_list_empty); } else { + // We increase the template depth before recursing into a requires-clause. + // + // This depth is used for setting up a LambdaScopeInfo (in + // Sema::RecordParsingTemplateParameterDepth), which is used later when + // inventing template parameters in InventTemplateParameter. + // + // This way, abbreviated generic lambdas could have different template + // depths, avoiding substitution into the wrong template parameters during + // constraint satisfaction check. + ++CurTemplateDepthTracker; ExprResult RequiresClause; if (TryConsumeToken(tok::kw_requires)) { RequiresClause = @@ -1396,7 +1406,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( Actions.ActOnLambdaExplicitTemplateParameterList( Intro, LAngleLoc, TemplateParams, RAngleLoc, RequiresClause); - ++CurTemplateDepthTracker; } } diff --git a/clang/test/Parser/cxx-concepts-requires-clause.cpp b/clang/test/Parser/cxx-concepts-requires-clause.cpp index 1ec1eef..5b5bc9e 100644 --- a/clang/test/Parser/cxx-concepts-requires-clause.cpp +++ b/clang/test/Parser/cxx-concepts-requires-clause.cpp @@ -168,3 +168,30 @@ auto lambda4 = [] requires(sizeof(char) == 1){}; // expected-error {{expected bo #if __cplusplus <= 202002L // expected-warning@-2{{lambda without a parameter clause is a C++23 extension}} #endif + +namespace GH78524 { + +template <typename T> T Foo; + +template <typename T> auto C(Foo<T>); + +template <typename T> struct D { + decltype(T()(C<T>)) Type; +}; + +template <typename T, typename U> D<T> G(T, U) { return {}; } + +struct E {}; + +void F() { + G([]<typename T> +// ~~~~~~~~~~ T: Depth: 0, Index: 0 + requires requires { [](auto...) {}; }(T) +// ~~~~ auto: Depth: 1, Index: 0 + { return T(); }, + E{}); +} + +int a = []<int=0> requires requires { [](auto){}; } { return 0; }(); + +} // namespace GH78524 |