[llvm-branch-commits] [clang] release/23.x: [clang-format] Harden star and amp annotation (#212856) (PR #216554)
Douglas Yung via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed Aug 26 00:29:25 PDT 2026
https://github.com/dyung updated https://github.com/llvm/llvm-project/pull/216554
>From 9ed5e6f4fc57bc8b8f1e6d4045d3cc0c5b57bb6c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Sch=C3=A4pers?= <bjoern at hazardy.de>
Date: Sat, 15 Aug 2026 11:56:28 +0200
Subject: [PATCH] [clang-format] Harden star and amp annotation (#212856)
At this point we can't (or won't) decide wether this is a template
argument or just an expression, opt out of the specialized (and in the
test cases wrong) assignment.
Fixes #212622
(cherry picked from commit af15d15f9bbd5ac5d3f020d270b38ffe01b0a72a)
[clang-format][NFC] Apply review comments (#218142)
That were missed while merging #212856.
(cherry picked from commit 8dba93818258d95c46fa2c17e902a8256e4d91b5)
---
clang/lib/Format/UnwrappedLineParser.cpp | 21 ++++++++++++++++---
clang/unittests/Format/TokenAnnotatorTest.cpp | 12 +++++++++++
2 files changed, 30 insertions(+), 3 deletions(-)
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index c9913e0627a21..5aada4883a7ef 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -2663,7 +2663,8 @@ bool UnwrappedLineParser::parseBracedList(bool IsAngleBracket, bool IsEnum) {
/// Parses a pair of parentheses (and everything between them).
/// \param StarAndAmpTokenType If different than TT_Unknown sets this type for
/// all (double) ampersands and stars. This applies for all nested scopes as
-/// well.
+/// well, this is disabled within a (potential) template argument <>, and thus
+/// also if we find only a <.
///
/// Returns whether there is a `=` token between the parentheses.
bool UnwrappedLineParser::parseParens(TokenType StarAndAmpTokenType,
@@ -2674,6 +2675,7 @@ bool UnwrappedLineParser::parseParens(TokenType StarAndAmpTokenType,
bool SeenComma = false;
bool SeenEqual = false;
bool MightBeFoldExpr = false;
+ unsigned ExcessLess = 0;
nextToken();
const bool MightBeStmtExpr = FormatTok->is(tok::l_brace);
if (!InMacroCall && Prev && Prev->is(TT_FunctionLikeMacro))
@@ -2681,8 +2683,10 @@ bool UnwrappedLineParser::parseParens(TokenType StarAndAmpTokenType,
do {
switch (FormatTok->Tok.getKind()) {
case tok::l_paren:
- if (parseParens(StarAndAmpTokenType, InMacroCall))
+ if (parseParens(ExcessLess == 0 ? StarAndAmpTokenType : TT_Unknown,
+ InMacroCall)) {
SeenEqual = true;
+ }
if (Style.isJava() && FormatTok->is(tok::l_brace))
parseChildBlock();
break;
@@ -2799,10 +2803,21 @@ bool UnwrappedLineParser::parseParens(TokenType StarAndAmpTokenType,
case tok::kw_requires:
parseRequiresExpression();
break;
+ case tok::less:
+ // We have here no clue whether this is a less, or a template opener, opt
+ // out of the predefined StarAndAmpTokenType.
+ ++ExcessLess;
+ nextToken();
+ break;
+ case tok::greater:
+ if (ExcessLess > 0)
+ --ExcessLess;
+ nextToken();
+ break;
case tok::star:
case tok::amp:
case tok::ampamp:
- if (StarAndAmpTokenType != TT_Unknown)
+ if (StarAndAmpTokenType != TT_Unknown && ExcessLess == 0)
FormatTok->setFinalizedType(StarAndAmpTokenType);
[[fallthrough]];
default:
diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp
index 8ef7e7387e269..5ff09578111d0 100644
--- a/clang/unittests/Format/TokenAnnotatorTest.cpp
+++ b/clang/unittests/Format/TokenAnnotatorTest.cpp
@@ -1579,6 +1579,18 @@ TEST_F(TokenAnnotatorTest, UnderstandsRequiresClausesAndConcepts) {
ASSERT_EQ(Tokens.size(), 18u) << Tokens;
EXPECT_TOKEN(Tokens[7], tok::kw_requires, TT_RequiresClause);
EXPECT_TOKEN(Tokens[12], tok::l_brace, TT_FunctionLBrace);
+
+ Tokens = annotate("template <typename T>\n"
+ " requires(is_convertible_v<const T&, Foo>)"
+ "void foo(T) {}");
+ ASSERT_EQ(Tokens.size(), 24u) << Tokens;
+ EXPECT_TOKEN(Tokens[11], tok::amp, TT_PointerOrReference);
+
+ Tokens = annotate("template <typename T>\n"
+ " requires(is_convertible_v<(const T&), Foo>)"
+ "void foo(T) {}");
+ ASSERT_EQ(Tokens.size(), 26u) << Tokens;
+ EXPECT_TOKEN(Tokens[12], tok::amp, TT_PointerOrReference);
}
TEST_F(TokenAnnotatorTest, UnderstandsRequiresExpressions) {
More information about the llvm-branch-commits
mailing list