diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -2134,7 +2134,7 @@ case tok::l_brace: break; case tok::l_paren: - parseParens(); + parseParens(/*AmpAmpTokenType=*/TT_PointerOrReference); break; case tok::l_square: parseSquare(); @@ -2211,6 +2211,12 @@ SeenArrow = true; nextToken(); break; + case tok::kw_requires: { + auto *RequiresToken = FormatTok; + nextToken(); + parseRequiresClause(RequiresToken); + break; + } default: return true; } @@ -3371,6 +3377,17 @@ // lambda to be possible. // template requires requires { ... } [[nodiscard]] ...; bool LambdaNextTimeAllowed = true; + + // Within lambda declarations, it is permitted to put a requires clause after + // its template parameter list, which would place the requires clause right + // before the parentheses of the parameters of the lambda declaration. Thus, + // we track if we expect to see grouping parentheses at all. + // Without this check, `requires foo (T t)` in the below example would be + // seen as the whole requires clause, accidentally eating the parameters of + // the lambda. + // [&] requires foo (T t) { ... }; + bool TopLevelParensAllowed = true; + do { bool LambdaThisTimeAllowed = std::exchange(LambdaNextTimeAllowed, false); @@ -3383,7 +3400,10 @@ } case tok::l_paren: + if (!TopLevelParensAllowed) + return; parseParens(/*AmpAmpTokenType=*/TT_BinaryOperator); + TopLevelParensAllowed = false; break; case tok::l_square: @@ -3407,6 +3427,7 @@ FormatTok->setFinalizedType(TT_BinaryOperator); nextToken(); LambdaNextTimeAllowed = true; + TopLevelParensAllowed = true; break; case tok::comma: @@ -3430,6 +3451,7 @@ case tok::star: case tok::slash: LambdaNextTimeAllowed = true; + TopLevelParensAllowed = true; // Just eat them. nextToken(); break; @@ -3438,6 +3460,7 @@ case tok::coloncolon: case tok::kw_true: case tok::kw_false: + TopLevelParensAllowed = false; // Just eat them. nextToken(); break; @@ -3486,6 +3509,7 @@ parseBracedList(/*ContinueOnSemicolons=*/false, /*IsEnum=*/false, /*ClosingBraceKind=*/tok::greater); } + TopLevelParensAllowed = false; break; } } while (!eof()); diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp --- a/clang/unittests/Format/TokenAnnotatorTest.cpp +++ b/clang/unittests/Format/TokenAnnotatorTest.cpp @@ -1279,6 +1279,110 @@ EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare); EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener); EXPECT_TOKEN(Tokens[7], tok::l_brace, TT_LambdaLBrace); + + // Lambdas with a requires-clause + Tokens = annotate("[] (T t) requires Bar {}"); + ASSERT_EQ(Tokens.size(), 18u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare); + EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener); + EXPECT_TOKEN(Tokens[10], tok::kw_requires, TT_RequiresClause); + EXPECT_TRUE(Tokens[14]->ClosesRequiresClause); + EXPECT_TOKEN(Tokens[15], tok::l_brace, TT_LambdaLBrace); + + Tokens = annotate("[] (T &&t) requires Bar {}"); + ASSERT_EQ(Tokens.size(), 19u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare); + EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener); + EXPECT_TOKEN(Tokens[8], tok::ampamp, TT_PointerOrReference); + EXPECT_TOKEN(Tokens[11], tok::kw_requires, TT_RequiresClause); + EXPECT_TRUE(Tokens[15]->ClosesRequiresClause); + EXPECT_TOKEN(Tokens[16], tok::l_brace, TT_LambdaLBrace); + + Tokens = annotate("[] (T t) requires Foo || Bar {}"); + ASSERT_EQ(Tokens.size(), 23u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare); + EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener); + EXPECT_TOKEN(Tokens[10], tok::kw_requires, TT_RequiresClause); + EXPECT_TRUE(Tokens[19]->ClosesRequiresClause); + EXPECT_TOKEN(Tokens[20], tok::l_brace, TT_LambdaLBrace); + + Tokens = annotate("[] (T t) -> T requires Bar {}"); + ASSERT_EQ(Tokens.size(), 20u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare); + EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener); + EXPECT_TOKEN(Tokens[10], tok::arrow, TT_LambdaArrow); + EXPECT_TOKEN(Tokens[12], tok::kw_requires, TT_RequiresClause); + EXPECT_TRUE(Tokens[16]->ClosesRequiresClause); + EXPECT_TOKEN(Tokens[17], tok::l_brace, TT_LambdaLBrace); + + Tokens = annotate("[] requires Bar (T t) {}"); + ASSERT_EQ(Tokens.size(), 18u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare); + EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener); + EXPECT_TOKEN(Tokens[6], tok::kw_requires, TT_RequiresClause); + EXPECT_TRUE(Tokens[10]->ClosesRequiresClause); + EXPECT_TOKEN(Tokens[15], tok::l_brace, TT_LambdaLBrace); + + Tokens = annotate("[] requires Bar (T &&t) {}"); + ASSERT_EQ(Tokens.size(), 19u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare); + EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener); + EXPECT_TOKEN(Tokens[6], tok::kw_requires, TT_RequiresClause); + EXPECT_TRUE(Tokens[10]->ClosesRequiresClause); + EXPECT_TOKEN(Tokens[13], tok::ampamp, TT_PointerOrReference); + EXPECT_TOKEN(Tokens[16], tok::l_brace, TT_LambdaLBrace); + + Tokens = annotate("[] requires Foo || Bar (T t) {}"); + ASSERT_EQ(Tokens.size(), 23u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare); + EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener); + EXPECT_TOKEN(Tokens[6], tok::kw_requires, TT_RequiresClause); + EXPECT_TRUE(Tokens[15]->ClosesRequiresClause); + EXPECT_TOKEN(Tokens[20], tok::l_brace, TT_LambdaLBrace); + + Tokens = annotate("[] requires true (T&& t) {}"); + ASSERT_EQ(Tokens.size(), 16u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare); + EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener); + EXPECT_TOKEN(Tokens[6], tok::kw_requires, TT_RequiresClause); + EXPECT_TRUE(Tokens[7]->ClosesRequiresClause); + EXPECT_TOKEN(Tokens[10], tok::ampamp, TT_PointerOrReference); + EXPECT_TOKEN(Tokens[13], tok::l_brace, TT_LambdaLBrace); + + Tokens = annotate("[] requires Bar {}"); + ASSERT_EQ(Tokens.size(), 14u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare); + EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener); + EXPECT_TOKEN(Tokens[6], tok::kw_requires, TT_RequiresClause); + EXPECT_TRUE(Tokens[10]->ClosesRequiresClause); + EXPECT_TOKEN(Tokens[11], tok::l_brace, TT_LambdaLBrace); + + Tokens = annotate("[] requires Bar noexcept {}"); + ASSERT_EQ(Tokens.size(), 15u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare); + EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener); + EXPECT_TOKEN(Tokens[6], tok::kw_requires, TT_RequiresClause); + EXPECT_TRUE(Tokens[10]->ClosesRequiresClause); + EXPECT_TOKEN(Tokens[12], tok::l_brace, TT_LambdaLBrace); + + Tokens = annotate("[] requires Bar -> T {}"); + ASSERT_EQ(Tokens.size(), 16u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare); + EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener); + EXPECT_TOKEN(Tokens[6], tok::kw_requires, TT_RequiresClause); + EXPECT_TRUE(Tokens[10]->ClosesRequiresClause); + EXPECT_TOKEN(Tokens[11], tok::arrow, TT_LambdaArrow); + EXPECT_TOKEN(Tokens[13], tok::l_brace, TT_LambdaLBrace); + + Tokens = annotate("[] requires Foo (T t) requires Bar {}"); + ASSERT_EQ(Tokens.size(), 23u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare); + EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener); + EXPECT_TOKEN(Tokens[6], tok::kw_requires, TT_RequiresClause); + EXPECT_TRUE(Tokens[10]->ClosesRequiresClause); + EXPECT_TOKEN(Tokens[15], tok::kw_requires, TT_RequiresClause); + EXPECT_TRUE(Tokens[19]->ClosesRequiresClause); + EXPECT_TOKEN(Tokens[20], tok::l_brace, TT_LambdaLBrace); } TEST_F(TokenAnnotatorTest, UnderstandsFunctionAnnotations) {