[clang] [clang-format] Allow default values for template parameters in lambda (PR #69052)

Emilia Kond via cfe-commits cfe-commits at lists.llvm.org
Sat Oct 14 07:00:51 PDT 2023


https://github.com/rymiel created https://github.com/llvm/llvm-project/pull/69052

Previously, upon encountering an equals sign while parsing a lambda in the UnwrappedLineParser, it would fall through and fail. This caused any lambda template with a default argument for a template parameter to be annotated as an ArraySubscriptLSquare.

This patch allows equals signs in the UnwrappedLineParser if we're currently in a template parameter list. This resolved a FIXME that was in the lambda parsing function.

This patch seems deceptively easy, it's likely it doesn't solve the FIXME entirely, or causes other issues (the FIXME itself mentions something about Objective-C, which I cannot comment about). However this patch is sufficient to fix the below issue.

Fixes https://github.com/llvm/llvm-project/issues/68913

>From 4f532ab0ae47bce011043f41cfac3ad3e601dd41 Mon Sep 17 00:00:00 2001
From: Emilia Kond <emilia at rymiel.space>
Date: Sat, 14 Oct 2023 16:52:31 +0300
Subject: [PATCH] [clang-format] Allow default values for template parameters
 in lambda

Previously, upon encountering an equals sign while parsing a lambda in
the UnwrappedLineParser, it would fall through and fail. This caused any
lambda template with a default argument for a template parameter to be
annotated as an ArraySubscriptLSquare.

This patch allows equals signs in the UnwrappedLineParser if we're
currently in a template parameter list. This resolved a FIXME that was
in the lambda parsing function.

This patch seems deceptively easy, it's likely it doesn't solve the
FIXME entirely, or causes other issues (the FIXME itself mentions
something about Objective-C, which I cannot comment about). However this
patch is sufficient to fix the below issue.

Fixes https://github.com/llvm/llvm-project/issues/68913
---
 clang/lib/Format/UnwrappedLineParser.cpp      |  9 +++--
 clang/unittests/Format/TokenAnnotatorTest.cpp | 38 +++++++++++++++++++
 2 files changed, 44 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index 82a812fc8bcc610..45a3fdbb5ba12e0 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -2226,9 +2226,6 @@ bool UnwrappedLineParser::tryToParseLambda() {
     // followed by an `a->b` expression, such as:
     // ([obj func:arg] + a->b)
     // Otherwise the code below would parse as a lambda.
-    //
-    // FIXME: This heuristic is incorrect for C++20 generic lambdas with
-    // explicit template lists: []<bool b = true && false>(U &&u){}
     case tok::plus:
     case tok::minus:
     case tok::exclaim:
@@ -2268,6 +2265,12 @@ bool UnwrappedLineParser::tryToParseLambda() {
       parseRequiresClause(RequiresToken);
       break;
     }
+    case tok::equal:
+      if (InTemplateParameterList) {
+        nextToken();
+        break;
+      }
+      return true;
     default:
       return true;
     }
diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp
index b6d4cf166de0281..f4f382cfe8f2494 100644
--- a/clang/unittests/Format/TokenAnnotatorTest.cpp
+++ b/clang/unittests/Format/TokenAnnotatorTest.cpp
@@ -1620,6 +1620,44 @@ TEST_F(TokenAnnotatorTest, UnderstandsLambdas) {
   EXPECT_TOKEN(Tokens[15], tok::kw_requires, TT_RequiresClause);
   EXPECT_TRUE(Tokens[19]->ClosesRequiresClause);
   EXPECT_TOKEN(Tokens[20], tok::l_brace, TT_LambdaLBrace);
+
+  Tokens = annotate("[] <typename T = int> (T t) {}");
+  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[7], tok::greater, TT_TemplateCloser);
+  EXPECT_TOKEN(Tokens[12], tok::l_brace, TT_LambdaLBrace);
+
+  Tokens = annotate("[] <int I = 0> (T t) {}");
+  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[7], tok::greater, TT_TemplateCloser);
+  EXPECT_TOKEN(Tokens[12], tok::l_brace, TT_LambdaLBrace);
+
+  Tokens = annotate("[] <bool b = false> (T t) {}");
+  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[7], tok::greater, TT_TemplateCloser);
+  EXPECT_TOKEN(Tokens[12], tok::l_brace, TT_LambdaLBrace);
+
+  Tokens = annotate("[] <bool b = true && false> (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[7], tok::ampamp, TT_BinaryOperator);
+  EXPECT_TOKEN(Tokens[9], tok::greater, TT_TemplateCloser);
+  EXPECT_TOKEN(Tokens[12], tok::ampamp, TT_PointerOrReference);
+  EXPECT_TOKEN(Tokens[15], tok::l_brace, TT_LambdaLBrace);
+
+  Tokens = annotate("[] <typename T = int> requires Foo<T> (T 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[7], tok::greater, TT_TemplateCloser);
+  EXPECT_TOKEN(Tokens[8], tok::kw_requires, TT_RequiresClause);
+  EXPECT_TOKEN(Tokens[17], tok::l_brace, TT_LambdaLBrace);
 }
 
 TEST_F(TokenAnnotatorTest, UnderstandsFunctionAnnotations) {



More information about the cfe-commits mailing list