[clang] [clang-format] Allow decltype in requires clause (PR #78847)

Emilia Kond via cfe-commits cfe-commits at lists.llvm.org
Mon Jan 22 04:41:26 PST 2024


https://github.com/rymiel updated https://github.com/llvm/llvm-project/pull/78847

>From 79ebbdc60cfa0635c9d889823a8b37710d9a4fb5 Mon Sep 17 00:00:00 2001
From: Emilia Kond <emilia at rymiel.space>
Date: Sat, 20 Jan 2024 15:44:16 +0200
Subject: [PATCH 1/3] [clang-format] Allow decltype in requires clause

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
---
 clang/lib/Format/UnwrappedLineParser.cpp      |  1 +
 clang/unittests/Format/TokenAnnotatorTest.cpp | 10 ++++++++++
 2 files changed, 11 insertions(+)

diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index c08ce86449b6ea..62a6018580a0d1 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -3433,6 +3433,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 64b2abac5cce53..3f94c464b41343 100644
--- a/clang/unittests/Format/TokenAnnotatorTest.cpp
+++ b/clang/unittests/Format/TokenAnnotatorTest.cpp
@@ -1071,6 +1071,16 @@ 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);
 }
 
 TEST_F(TokenAnnotatorTest, UnderstandsRequiresExpressions) {

>From bef8c027504e1e0c0f28da090e1859be714a3ab1 Mon Sep 17 00:00:00 2001
From: Emilia Kond <emilia at rymiel.space>
Date: Mon, 22 Jan 2024 00:31:23 +0200
Subject: [PATCH 2/3] address review and add more tests

---
 clang/lib/Format/UnwrappedLineParser.cpp      |  9 +++++---
 clang/unittests/Format/TokenAnnotatorTest.cpp | 21 +++++++++++++++++++
 2 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index 62a6018580a0d1..75721a3f79eca8 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -3423,9 +3423,12 @@ bool clang::format::UnwrappedLineParser::parseRequires() {
       break;
     case tok::r_paren:
     case tok::pipepipe:
-      FormatTok = Tokens->setPosition(StoredPosition);
-      parseRequiresClause(RequiresToken);
-      return true;
+      if (OpenAngles == 0) {
+        FormatTok = Tokens->setPosition(StoredPosition);
+        parseRequiresClause(RequiresToken);
+        return true;
+      }
+      break;
     case tok::eof:
       // Break out of the loop.
       Lookahead = 50;
diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp
index 3f94c464b41343..a1b24dc86bf0ff 100644
--- a/clang/unittests/Format/TokenAnnotatorTest.cpp
+++ b/clang/unittests/Format/TokenAnnotatorTest.cpp
@@ -1081,6 +1081,27 @@ TEST_F(TokenAnnotatorTest, UnderstandsRequiresClausesAndConcepts) {
   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("int foo(auto t) {\n"
+                    "    if (requires (decltype(t) x) {x.foo();}) {\n"
+                    "        return 1;\n"
+                    "    }\n"
+                    "    return 0;\n"
+                    "}\n");
+  ASSERT_EQ(Tokens.size(), 36u) << Tokens;
+  EXPECT_TOKEN(Tokens[9], tok::kw_requires, TT_RequiresExpression);
+
+  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) {

>From 5d3909aed5342e9c0b78513199b149eae6cc5991 Mon Sep 17 00:00:00 2001
From: Emilia Kond <emilia at rymiel.space>
Date: Mon, 22 Jan 2024 14:40:34 +0200
Subject: [PATCH 3/3] remove the check, remove test that doesn't use
 parseRequires

---
 clang/lib/Format/UnwrappedLineParser.cpp      | 8 --------
 clang/unittests/Format/TokenAnnotatorTest.cpp | 9 ---------
 2 files changed, 17 deletions(-)

diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index 75721a3f79eca8..f9295e926e1970 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -3421,14 +3421,6 @@ bool clang::format::UnwrappedLineParser::parseRequires() {
         return false;
       }
       break;
-    case tok::r_paren:
-    case tok::pipepipe:
-      if (OpenAngles == 0) {
-        FormatTok = Tokens->setPosition(StoredPosition);
-        parseRequiresClause(RequiresToken);
-        return true;
-      }
-      break;
     case tok::eof:
       // Break out of the loop.
       Lookahead = 50;
diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp
index a1b24dc86bf0ff..167138fcbe4148 100644
--- a/clang/unittests/Format/TokenAnnotatorTest.cpp
+++ b/clang/unittests/Format/TokenAnnotatorTest.cpp
@@ -1082,15 +1082,6 @@ TEST_F(TokenAnnotatorTest, UnderstandsRequiresClausesAndConcepts) {
   EXPECT_TOKEN(Tokens[6], tok::amp, TT_PointerOrReference);
   EXPECT_TOKEN(Tokens[7], tok::kw_requires, TT_RequiresClause);
 
-  Tokens = annotate("int foo(auto t) {\n"
-                    "    if (requires (decltype(t) x) {x.foo();}) {\n"
-                    "        return 1;\n"
-                    "    }\n"
-                    "    return 0;\n"
-                    "}\n");
-  ASSERT_EQ(Tokens.size(), 36u) << Tokens;
-  EXPECT_TOKEN(Tokens[9], tok::kw_requires, TT_RequiresExpression);
-
   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);



More information about the cfe-commits mailing list