Skip to content

Commit 5409fb3

Browse files
committed
[clang-format] Annotate lambdas with requires clauses.
The C++ grammar allows lambdas to have a *requires-clause* in two places, either directly after the *template-parameter-list*, such as: `[] <typename T> requires foo<T> (T t) { ... };` Or, at the end of the *lambda-declarator* (before the lambda's body): `[] <typename T> (T t) requires foo<T> { ... };` Previously, these cases weren't handled at all, resulting in weird results. Note that this commit only handles token annotation, so the actual formatting still ends up suboptimal. This is mostly because I do not yet know how to approach making the requires clause formatting of lambdas match the formatting for functions. Fixes #61269 Reviewed By: HazardyKnusperkeks, owenpan Differential Revision: https://reviews.llvm.org/D145642
1 parent cd67bbd commit 5409fb3

File tree

2 files changed

+129
-1
lines changed

2 files changed

+129
-1
lines changed

clang/lib/Format/UnwrappedLineParser.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2134,7 +2134,7 @@ bool UnwrappedLineParser::tryToParseLambda() {
21342134
case tok::l_brace:
21352135
break;
21362136
case tok::l_paren:
2137-
parseParens();
2137+
parseParens(/*AmpAmpTokenType=*/TT_PointerOrReference);
21382138
break;
21392139
case tok::l_square:
21402140
parseSquare();
@@ -2211,6 +2211,12 @@ bool UnwrappedLineParser::tryToParseLambda() {
22112211
SeenArrow = true;
22122212
nextToken();
22132213
break;
2214+
case tok::kw_requires: {
2215+
auto *RequiresToken = FormatTok;
2216+
nextToken();
2217+
parseRequiresClause(RequiresToken);
2218+
break;
2219+
}
22142220
default:
22152221
return true;
22162222
}
@@ -3371,6 +3377,17 @@ void UnwrappedLineParser::parseConstraintExpression() {
33713377
// lambda to be possible.
33723378
// template <typename T> requires requires { ... } [[nodiscard]] ...;
33733379
bool LambdaNextTimeAllowed = true;
3380+
3381+
// Within lambda declarations, it is permitted to put a requires clause after
3382+
// its template parameter list, which would place the requires clause right
3383+
// before the parentheses of the parameters of the lambda declaration. Thus,
3384+
// we track if we expect to see grouping parentheses at all.
3385+
// Without this check, `requires foo<T> (T t)` in the below example would be
3386+
// seen as the whole requires clause, accidentally eating the parameters of
3387+
// the lambda.
3388+
// [&]<typename T> requires foo<T> (T t) { ... };
3389+
bool TopLevelParensAllowed = true;
3390+
33743391
do {
33753392
bool LambdaThisTimeAllowed = std::exchange(LambdaNextTimeAllowed, false);
33763393

@@ -3383,7 +3400,10 @@ void UnwrappedLineParser::parseConstraintExpression() {
33833400
}
33843401

33853402
case tok::l_paren:
3403+
if (!TopLevelParensAllowed)
3404+
return;
33863405
parseParens(/*AmpAmpTokenType=*/TT_BinaryOperator);
3406+
TopLevelParensAllowed = false;
33873407
break;
33883408

33893409
case tok::l_square:
@@ -3407,6 +3427,7 @@ void UnwrappedLineParser::parseConstraintExpression() {
34073427
FormatTok->setFinalizedType(TT_BinaryOperator);
34083428
nextToken();
34093429
LambdaNextTimeAllowed = true;
3430+
TopLevelParensAllowed = true;
34103431
break;
34113432

34123433
case tok::comma:
@@ -3430,6 +3451,7 @@ void UnwrappedLineParser::parseConstraintExpression() {
34303451
case tok::star:
34313452
case tok::slash:
34323453
LambdaNextTimeAllowed = true;
3454+
TopLevelParensAllowed = true;
34333455
// Just eat them.
34343456
nextToken();
34353457
break;
@@ -3438,6 +3460,7 @@ void UnwrappedLineParser::parseConstraintExpression() {
34383460
case tok::coloncolon:
34393461
case tok::kw_true:
34403462
case tok::kw_false:
3463+
TopLevelParensAllowed = false;
34413464
// Just eat them.
34423465
nextToken();
34433466
break;
@@ -3486,6 +3509,7 @@ void UnwrappedLineParser::parseConstraintExpression() {
34863509
parseBracedList(/*ContinueOnSemicolons=*/false, /*IsEnum=*/false,
34873510
/*ClosingBraceKind=*/tok::greater);
34883511
}
3512+
TopLevelParensAllowed = false;
34893513
break;
34903514
}
34913515
} while (!eof());

clang/unittests/Format/TokenAnnotatorTest.cpp

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1279,6 +1279,110 @@ TEST_F(TokenAnnotatorTest, UnderstandsLambdas) {
12791279
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
12801280
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
12811281
EXPECT_TOKEN(Tokens[7], tok::l_brace, TT_LambdaLBrace);
1282+
1283+
// Lambdas with a requires-clause
1284+
Tokens = annotate("[] <typename T> (T t) requires Bar<T> {}");
1285+
ASSERT_EQ(Tokens.size(), 18u) << Tokens;
1286+
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
1287+
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
1288+
EXPECT_TOKEN(Tokens[10], tok::kw_requires, TT_RequiresClause);
1289+
EXPECT_TRUE(Tokens[14]->ClosesRequiresClause);
1290+
EXPECT_TOKEN(Tokens[15], tok::l_brace, TT_LambdaLBrace);
1291+
1292+
Tokens = annotate("[] <typename T> (T &&t) requires Bar<T> {}");
1293+
ASSERT_EQ(Tokens.size(), 19u) << Tokens;
1294+
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
1295+
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
1296+
EXPECT_TOKEN(Tokens[8], tok::ampamp, TT_PointerOrReference);
1297+
EXPECT_TOKEN(Tokens[11], tok::kw_requires, TT_RequiresClause);
1298+
EXPECT_TRUE(Tokens[15]->ClosesRequiresClause);
1299+
EXPECT_TOKEN(Tokens[16], tok::l_brace, TT_LambdaLBrace);
1300+
1301+
Tokens = annotate("[] <typename T> (T t) requires Foo<T> || Bar<T> {}");
1302+
ASSERT_EQ(Tokens.size(), 23u) << Tokens;
1303+
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
1304+
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
1305+
EXPECT_TOKEN(Tokens[10], tok::kw_requires, TT_RequiresClause);
1306+
EXPECT_TRUE(Tokens[19]->ClosesRequiresClause);
1307+
EXPECT_TOKEN(Tokens[20], tok::l_brace, TT_LambdaLBrace);
1308+
1309+
Tokens = annotate("[] <typename T> (T t) -> T requires Bar<T> {}");
1310+
ASSERT_EQ(Tokens.size(), 20u) << Tokens;
1311+
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
1312+
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
1313+
EXPECT_TOKEN(Tokens[10], tok::arrow, TT_LambdaArrow);
1314+
EXPECT_TOKEN(Tokens[12], tok::kw_requires, TT_RequiresClause);
1315+
EXPECT_TRUE(Tokens[16]->ClosesRequiresClause);
1316+
EXPECT_TOKEN(Tokens[17], tok::l_brace, TT_LambdaLBrace);
1317+
1318+
Tokens = annotate("[] <typename T> requires Bar<T> (T t) {}");
1319+
ASSERT_EQ(Tokens.size(), 18u) << Tokens;
1320+
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
1321+
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
1322+
EXPECT_TOKEN(Tokens[6], tok::kw_requires, TT_RequiresClause);
1323+
EXPECT_TRUE(Tokens[10]->ClosesRequiresClause);
1324+
EXPECT_TOKEN(Tokens[15], tok::l_brace, TT_LambdaLBrace);
1325+
1326+
Tokens = annotate("[] <typename T> requires Bar<T> (T &&t) {}");
1327+
ASSERT_EQ(Tokens.size(), 19u) << Tokens;
1328+
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
1329+
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
1330+
EXPECT_TOKEN(Tokens[6], tok::kw_requires, TT_RequiresClause);
1331+
EXPECT_TRUE(Tokens[10]->ClosesRequiresClause);
1332+
EXPECT_TOKEN(Tokens[13], tok::ampamp, TT_PointerOrReference);
1333+
EXPECT_TOKEN(Tokens[16], tok::l_brace, TT_LambdaLBrace);
1334+
1335+
Tokens = annotate("[] <typename T> requires Foo<T> || Bar<T> (T t) {}");
1336+
ASSERT_EQ(Tokens.size(), 23u) << Tokens;
1337+
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
1338+
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
1339+
EXPECT_TOKEN(Tokens[6], tok::kw_requires, TT_RequiresClause);
1340+
EXPECT_TRUE(Tokens[15]->ClosesRequiresClause);
1341+
EXPECT_TOKEN(Tokens[20], tok::l_brace, TT_LambdaLBrace);
1342+
1343+
Tokens = annotate("[] <typename T> requires true (T&& t) {}");
1344+
ASSERT_EQ(Tokens.size(), 16u) << Tokens;
1345+
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
1346+
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
1347+
EXPECT_TOKEN(Tokens[6], tok::kw_requires, TT_RequiresClause);
1348+
EXPECT_TRUE(Tokens[7]->ClosesRequiresClause);
1349+
EXPECT_TOKEN(Tokens[10], tok::ampamp, TT_PointerOrReference);
1350+
EXPECT_TOKEN(Tokens[13], tok::l_brace, TT_LambdaLBrace);
1351+
1352+
Tokens = annotate("[] <typename T> requires Bar<T> {}");
1353+
ASSERT_EQ(Tokens.size(), 14u) << Tokens;
1354+
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
1355+
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
1356+
EXPECT_TOKEN(Tokens[6], tok::kw_requires, TT_RequiresClause);
1357+
EXPECT_TRUE(Tokens[10]->ClosesRequiresClause);
1358+
EXPECT_TOKEN(Tokens[11], tok::l_brace, TT_LambdaLBrace);
1359+
1360+
Tokens = annotate("[] <typename T> requires Bar<T> noexcept {}");
1361+
ASSERT_EQ(Tokens.size(), 15u) << Tokens;
1362+
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
1363+
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
1364+
EXPECT_TOKEN(Tokens[6], tok::kw_requires, TT_RequiresClause);
1365+
EXPECT_TRUE(Tokens[10]->ClosesRequiresClause);
1366+
EXPECT_TOKEN(Tokens[12], tok::l_brace, TT_LambdaLBrace);
1367+
1368+
Tokens = annotate("[] <typename T> requires Bar<T> -> T {}");
1369+
ASSERT_EQ(Tokens.size(), 16u) << Tokens;
1370+
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
1371+
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
1372+
EXPECT_TOKEN(Tokens[6], tok::kw_requires, TT_RequiresClause);
1373+
EXPECT_TRUE(Tokens[10]->ClosesRequiresClause);
1374+
EXPECT_TOKEN(Tokens[11], tok::arrow, TT_LambdaArrow);
1375+
EXPECT_TOKEN(Tokens[13], tok::l_brace, TT_LambdaLBrace);
1376+
1377+
Tokens = annotate("[] <typename T> requires Foo<T> (T t) requires Bar<T> {}");
1378+
ASSERT_EQ(Tokens.size(), 23u) << Tokens;
1379+
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
1380+
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
1381+
EXPECT_TOKEN(Tokens[6], tok::kw_requires, TT_RequiresClause);
1382+
EXPECT_TRUE(Tokens[10]->ClosesRequiresClause);
1383+
EXPECT_TOKEN(Tokens[15], tok::kw_requires, TT_RequiresClause);
1384+
EXPECT_TRUE(Tokens[19]->ClosesRequiresClause);
1385+
EXPECT_TOKEN(Tokens[20], tok::l_brace, TT_LambdaLBrace);
12821386
}
12831387

12841388
TEST_F(TokenAnnotatorTest, UnderstandsFunctionAnnotations) {

0 commit comments

Comments
 (0)