Skip to content

Commit 19e518d

Browse files
authored
[Clang][Parser] Have the depth of the abbreviated generic lambdas inside a requires clause differ from the surrounding generic lambda (llvm#80656)
A one-line fix, again : ) This fixes llvm#78524 and the similar example at llvm#78524 (comment). 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.
1 parent 590c968 commit 19e518d

File tree

3 files changed

+41
-1
lines changed

3 files changed

+41
-1
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,10 @@ Bug Fixes to C++ Support
277277
(`#82258 <https://github.com/llvm/llvm-project/issues/82258>`_)
278278
- Correctly immediate-escalate lambda conversion functions.
279279
(`#82258 <https://github.com/llvm/llvm-project/issues/82258>`_)
280+
- Fixed an issue where template parameters of a nested abbreviated generic lambda within
281+
a requires-clause lie at the same depth as those of the surrounding lambda. This,
282+
in turn, results in the wrong template argument substitution during constraint checking.
283+
(`#78524 <https://github.com/llvm/llvm-project/issues/78524>`_)
280284

281285
Bug Fixes to AST Handling
282286
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Parse/ParseExprCXX.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1385,6 +1385,16 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
13851385
Diag(RAngleLoc,
13861386
diag::err_lambda_template_parameter_list_empty);
13871387
} else {
1388+
// We increase the template depth before recursing into a requires-clause.
1389+
//
1390+
// This depth is used for setting up a LambdaScopeInfo (in
1391+
// Sema::RecordParsingTemplateParameterDepth), which is used later when
1392+
// inventing template parameters in InventTemplateParameter.
1393+
//
1394+
// This way, abbreviated generic lambdas could have different template
1395+
// depths, avoiding substitution into the wrong template parameters during
1396+
// constraint satisfaction check.
1397+
++CurTemplateDepthTracker;
13881398
ExprResult RequiresClause;
13891399
if (TryConsumeToken(tok::kw_requires)) {
13901400
RequiresClause =
@@ -1396,7 +1406,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
13961406

13971407
Actions.ActOnLambdaExplicitTemplateParameterList(
13981408
Intro, LAngleLoc, TemplateParams, RAngleLoc, RequiresClause);
1399-
++CurTemplateDepthTracker;
14001409
}
14011410
}
14021411

clang/test/Parser/cxx-concepts-requires-clause.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,3 +168,30 @@ auto lambda4 = [] requires(sizeof(char) == 1){}; // expected-error {{expected bo
168168
#if __cplusplus <= 202002L
169169
// expected-warning@-2{{lambda without a parameter clause is a C++23 extension}}
170170
#endif
171+
172+
namespace GH78524 {
173+
174+
template <typename T> T Foo;
175+
176+
template <typename T> auto C(Foo<T>);
177+
178+
template <typename T> struct D {
179+
decltype(T()(C<T>)) Type;
180+
};
181+
182+
template <typename T, typename U> D<T> G(T, U) { return {}; }
183+
184+
struct E {};
185+
186+
void F() {
187+
G([]<typename T>
188+
// ~~~~~~~~~~ T: Depth: 0, Index: 0
189+
requires requires { [](auto...) {}; }(T)
190+
// ~~~~ auto: Depth: 1, Index: 0
191+
{ return T(); },
192+
E{});
193+
}
194+
195+
int a = []<int=0> requires requires { [](auto){}; } { return 0; }();
196+
197+
} // namespace GH78524

0 commit comments

Comments
 (0)