aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYounan Zhang <zyn7109@gmail.com>2024-02-23 09:36:32 +0800
committerGitHub <noreply@github.com>2024-02-23 09:36:32 +0800
commit19e518d2623c0e87a87ebf30405e74448bd1ee70 (patch)
tree88e9793f389bb04a56b30fb65ac845fe55161901
parent590c968e7943e51bb00ff75d312435f24d983b2a (diff)
downloadllvm-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.rst4
-rw-r--r--clang/lib/Parse/ParseExprCXX.cpp11
-rw-r--r--clang/test/Parser/cxx-concepts-requires-clause.cpp27
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