Skip to content

Commit

Permalink
[clang-format] Allow decltype in requires clause (#78847)
Browse files Browse the repository at this point in the history
If clang-format is not sure whether a `requires` keyword starts a
requires clause or a requires expression, it looks ahead to see if any
token disqualifies it from being a requires clause. Among these tokens
was `decltype`, since it fell through the switch.

This patch allows decltype to exist in a require clause.

I'm not 100% sure this change won't have repercussions, but that just
means we need more test coverage!

Fixes #78645
  • Loading branch information
rymiel committed Feb 1, 2024
1 parent b777bb7 commit 9b68c09
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 5 deletions.
6 changes: 1 addition & 5 deletions clang/lib/Format/UnwrappedLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3446,18 +3446,14 @@ bool clang::format::UnwrappedLineParser::parseRequires() {
return false;
}
break;
case tok::r_paren:
case tok::pipepipe:
FormatTok = Tokens->setPosition(StoredPosition);
parseRequiresClause(RequiresToken);
return true;
case tok::eof:
// Break out of the loop.
Lookahead = 50;
break;
case tok::coloncolon:
LastWasColonColon = true;
break;
case tok::kw_decltype:
case tok::identifier:
if (FoundType && !LastWasColonColon && OpenAngles == 0) {
FormatTok = Tokens->setPosition(StoredPosition);
Expand Down
22 changes: 22 additions & 0 deletions clang/unittests/Format/TokenAnnotatorTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1076,6 +1076,28 @@ TEST_F(TokenAnnotatorTest, UnderstandsRequiresClausesAndConcepts) {
"concept C = (!Foo<T>) && Bar;");
ASSERT_EQ(Tokens.size(), 19u) << Tokens;
EXPECT_TOKEN(Tokens[15], tok::ampamp, TT_BinaryOperator);

Tokens = annotate("void f() & requires(C<decltype(x)>) {}");
ASSERT_EQ(Tokens.size(), 18u) << Tokens;
EXPECT_TOKEN(Tokens[4], tok::amp, TT_PointerOrReference);
EXPECT_TOKEN(Tokens[5], tok::kw_requires, TT_RequiresClause);

Tokens = annotate("auto f() -> int& requires(C<decltype(x)>) {}");
ASSERT_EQ(Tokens.size(), 20u) << Tokens;
EXPECT_TOKEN(Tokens[6], tok::amp, TT_PointerOrReference);
EXPECT_TOKEN(Tokens[7], tok::kw_requires, TT_RequiresClause);

Tokens = annotate("bool x = t && requires(decltype(t) x) { x.foo(); };");
ASSERT_EQ(Tokens.size(), 23u) << Tokens;
EXPECT_TOKEN(Tokens[5], tok::kw_requires, TT_RequiresExpression);

Tokens = annotate("bool x = t && requires(Foo<decltype(t)> x) { x.foo(); };");
ASSERT_EQ(Tokens.size(), 26u) << Tokens;
EXPECT_TOKEN(Tokens[5], tok::kw_requires, TT_RequiresExpression);

Tokens = annotate("bool x = t && requires(Foo<C1 || C2> x) { x.foo(); };");
ASSERT_EQ(Tokens.size(), 25u) << Tokens;
EXPECT_TOKEN(Tokens[5], tok::kw_requires, TT_RequiresExpression);
}

TEST_F(TokenAnnotatorTest, UnderstandsRequiresExpressions) {
Expand Down

0 comments on commit 9b68c09

Please sign in to comment.