summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEmilia Kond <emilia@rymiel.space>2024-02-01 08:00:45 +0200
committerGitHub <noreply@github.com>2024-02-01 08:00:45 +0200
commit9b68c095d6b52d6ec0390c653528f65c42e5f570 (patch)
tree622dc389ec660ec03ba7994ec680a9405f47e863
parentb777bb78b302055eba876a0258ea4b2625ffe71a (diff)
[clang-format] Allow decltype in requires clause (#78847)
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 https://github.com/llvm/llvm-project/issues/78645
-rw-r--r--clang/lib/Format/UnwrappedLineParser.cpp6
-rw-r--r--clang/unittests/Format/TokenAnnotatorTest.cpp22
2 files changed, 23 insertions, 5 deletions
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index b904e0e56d9e..0a7f8808f29a 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -3446,11 +3446,6 @@ 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;
@@ -3458,6 +3453,7 @@ bool clang::format::UnwrappedLineParser::parseRequires() {
case tok::coloncolon:
LastWasColonColon = true;
break;
+ case tok::kw_decltype:
case tok::identifier:
if (FoundType && !LastWasColonColon && OpenAngles == 0) {
FormatTok = Tokens->setPosition(StoredPosition);
diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp
index f3e443e8829b..6e5832858c1e 100644
--- a/clang/unittests/Format/TokenAnnotatorTest.cpp
+++ b/clang/unittests/Format/TokenAnnotatorTest.cpp
@@ -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) {