rymiel updated this revision to Diff 503753. rymiel added a comment. Improve code flow in parseConstraintExpression
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D145642/new/ https://reviews.llvm.org/D145642 Files: clang/lib/Format/UnwrappedLineParser.cpp clang/unittests/Format/TokenAnnotatorTest.cpp
Index: clang/unittests/Format/TokenAnnotatorTest.cpp =================================================================== --- clang/unittests/Format/TokenAnnotatorTest.cpp +++ clang/unittests/Format/TokenAnnotatorTest.cpp @@ -1263,6 +1263,102 @@ 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("[] <typename T> (T t) requires Bar<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[10], tok::kw_requires, TT_RequiresClause); + EXPECT_TRUE(Tokens[14]->ClosesRequiresClause); + EXPECT_TOKEN(Tokens[15], tok::l_brace, TT_LambdaLBrace); + + Tokens = annotate("[] <typename T> (T &&t) requires Bar<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[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("[] <typename T> (T t) requires Foo<T> || Bar<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[10], tok::kw_requires, TT_RequiresClause); + EXPECT_TRUE(Tokens[19]->ClosesRequiresClause); + EXPECT_TOKEN(Tokens[20], tok::l_brace, TT_LambdaLBrace); + + Tokens = annotate("[] <typename T> (T t) -> T requires Bar<T> {}"); + 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("[] <typename T> requires Bar<T> (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("[] <typename T> requires Bar<T> (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("[] <typename T> requires Foo<T> || Bar<T> (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("[] <typename T> requires Bar<T> {}"); + 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("[] <typename T> requires Bar<T> 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("[] <typename T> requires Bar<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[10]->ClosesRequiresClause); + EXPECT_TOKEN(Tokens[11], tok::arrow, TT_LambdaArrow); + EXPECT_TOKEN(Tokens[13], tok::l_brace, TT_LambdaLBrace); + + // Both at once? Probably not even valid. + Tokens = annotate("[] <typename T> requires Foo<T> (T t) requires Bar<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[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) { Index: clang/lib/Format/UnwrappedLineParser.cpp =================================================================== --- clang/lib/Format/UnwrappedLineParser.cpp +++ clang/lib/Format/UnwrappedLineParser.cpp @@ -2129,7 +2129,7 @@ case tok::l_brace: break; case tok::l_paren: - parseParens(); + parseParens(/*AmpAmpTokenType=*/TT_PointerOrReference); break; case tok::l_square: parseSquare(); @@ -2206,6 +2206,12 @@ SeenArrow = true; nextToken(); break; + case tok::kw_requires: { + auto *RequiresToken = FormatTok; + nextToken(); + parseRequiresClause(RequiresToken); + break; + } default: return true; } @@ -3357,6 +3363,17 @@ // lambda to be possible. // template <typename T> 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 t)` in the below example would be + // seen as the whole requires clause, accidentally eating the parameters of + // the lambda. + // [&]<typename T> requires foo<T> (T t) { ... }; + bool TopLevelParensAllowed = true; + do { bool LambdaThisTimeAllowed = std::exchange(LambdaNextTimeAllowed, false); @@ -3369,7 +3386,10 @@ } case tok::l_paren: + if (!TopLevelParensAllowed) + return; parseParens(/*AmpAmpTokenType=*/TT_BinaryOperator); + TopLevelParensAllowed = false; break; case tok::l_square: @@ -3393,6 +3413,7 @@ FormatTok->setFinalizedType(TT_BinaryOperator); nextToken(); LambdaNextTimeAllowed = true; + TopLevelParensAllowed = true; break; case tok::comma: @@ -3416,6 +3437,7 @@ case tok::star: case tok::slash: LambdaNextTimeAllowed = true; + TopLevelParensAllowed = true; // Just eat them. nextToken(); break; @@ -3472,6 +3494,7 @@ parseBracedList(/*ContinueOnSemicolons=*/false, /*IsEnum=*/false, /*ClosingBraceKind=*/tok::greater); } + TopLevelParensAllowed = false; break; } } while (!eof());
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits