Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 2 commits into from
Oct 16, 2023

Conversation

rymiel
Copy link
Member

@rymiel rymiel commented Oct 14, 2023

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 #68913

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 llvm#68913
@llvmbot
Copy link
Collaborator

llvmbot commented Oct 14, 2023

@llvm/pr-subscribers-clang-format

Author: Emilia Kond (rymiel)

Changes

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 #68913


Full diff: https://github.com/llvm/llvm-project/pull/69052.diff

2 Files Affected:

  • (modified) clang/lib/Format/UnwrappedLineParser.cpp (+6-3)
  • (modified) clang/unittests/Format/TokenAnnotatorTest.cpp (+38)
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) {

clang/lib/Format/UnwrappedLineParser.cpp Outdated Show resolved Hide resolved
Co-authored-by: Owen Pan <owenpiano@gmail.com>
@rymiel rymiel merged commit 5f4ed78 into llvm:main Oct 16, 2023
3 checks passed
@rymiel rymiel deleted the format/lambda-template-equals branch October 16, 2023 21:38
@owenca
Copy link
Contributor

owenca commented Oct 23, 2023

@rymiel, thanks for the co-authorship, but I really didn't deserve it here!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[clang-format] Template lambda function is divided into two lines
4 participants