[clang] 2ef41cc - [clang-format] Fix Macros configuration not working with try/catch expansions (#184891)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Mar 17 12:46:22 PDT 2026
Author: Harris Hancock
Date: 2026-03-17T20:46:17+01:00
New Revision: 2ef41cca149cf133683cd70f6002b3d885842356
URL: https://github.com/llvm/llvm-project/commit/2ef41cca149cf133683cd70f6002b3d885842356
DIFF: https://github.com/llvm/llvm-project/commit/2ef41cca149cf133683cd70f6002b3d885842356.diff
LOG: [clang-format] Fix Macros configuration not working with try/catch expansions (#184891)
This is a superseding followup to my previous PR,
https://github.com/llvm/llvm-project/pull/183352.
In my previous PR, I proposed adding TryMacros and CatchMacros
configuration options, similar in spirit to IfMacros and ForEachMacros.
I did so because I noticed that configuration like
`Macros=["TRY_MACRO=try", "CATCH_MACRO(e)=catch(e)]` did not format
configured macro(s) as try/catch blocks. @owenca confirmed in my
previous PR that this observed behavior is undesired, and we should
prefer to fix it rather than introduce new features.
This PR proposes a fix, described in detail in the commit message below
the break. In general terms, it deletes a heuristic from the lexing
phase, where it interacted poorly with the Macros option, and moves its
functionality to the parsing phase instead.
I describe a possibly cleaner fix in [a comment
here](https://github.com/llvm/llvm-project/pull/183352#issuecomment-3992773126),
but it has the disadvantage of unintended behavior changes for
Objective-C code using `try` as an identifier. The fix in this PR avoids
that unintended behavior change; the only behavior change is the bugfix
itself.
cc @HazardyKnusperkeks as previous reviewer, and @mydeveloperday as the
heuristic's original author.
---
The lexer heuristic `tryTransformTryUsageForC()` was intended to allow C
code to use `try` as an identifier by demoting `tok::kw_try` to
`tok::identifier` when the following token did not look like the start
of a try body. However, when `MacroExpander::parseDefinition()` lexed a
macro like `"TRY_MACRO=try"`, the `try` token in the expansion body was
followed by `eof`, triggering the heuristic. This caused `try` to be
demoted to an identifier in the macro definition, so expanded code was
never parsed as a try/catch statement.
Delete `tryTransformTryUsageForC()` and instead guard the two `case
tok::kw_try:` dispatch sites in
`UnwrappedLineParser::parseStructuralElement()`. The guard is restricted
to `Style.isCpp()` (which covers C, C++, and Objective-C) and checks
whether the next non-comment token is `{`, `:`, or `#` -- the tokens
that can legitimately begin a try body or precede one.
The old heuristic also had to check for a preceding `@` token to avoid
demoting `try` in Objective-C `@try` constructs. The parser-level guard
does not need this check because `@try` is routed through `case tok::at`
and dispatched via `getObjCKeywordID()` to `tok::objc_try`, which calls
`parseTryCatch()` directly. The bare `kw_try` token never reaches `case
tok::kw_try` when parsing `@try`.
Assisted-by: Claude (anthropic.com)
Added:
Modified:
clang/lib/Format/FormatTokenLexer.cpp
clang/lib/Format/FormatTokenLexer.h
clang/unittests/Format/FormatTest.cpp
Removed:
################################################################################
diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp
index 4a087d9e6dc2b..0dc6f776aeca0 100644
--- a/clang/lib/Format/FormatTokenLexer.cpp
+++ b/clang/lib/Format/FormatTokenLexer.cpp
@@ -163,8 +163,6 @@ void FormatTokenLexer::tryMergePreviousTokens() {
return;
if (tryMergeForEach())
return;
- if (Style.isCpp() && tryTransformTryUsageForC())
- return;
if ((Style.Language == FormatStyle::LK_Cpp ||
Style.Language == FormatStyle::LK_ObjC) &&
@@ -533,26 +531,6 @@ bool FormatTokenLexer::tryMergeForEach() {
return true;
}
-bool FormatTokenLexer::tryTransformTryUsageForC() {
- if (Tokens.size() < 2)
- return false;
- auto &Try = *(Tokens.end() - 2);
- if (Try->isNot(tok::kw_try))
- return false;
- auto &Next = *(Tokens.end() - 1);
- if (Next->isOneOf(tok::l_brace, tok::colon, tok::hash, tok::comment))
- return false;
-
- if (Tokens.size() > 2) {
- auto &At = *(Tokens.end() - 3);
- if (At->is(tok::at))
- return false;
- }
-
- Try->Tok.setKind(tok::identifier);
- return true;
-}
-
bool FormatTokenLexer::tryMergeLessLess() {
// Merge X,less,less,Y into X,lessless,Y unless X or Y is less.
if (Tokens.size() < 3)
diff --git a/clang/lib/Format/FormatTokenLexer.h b/clang/lib/Format/FormatTokenLexer.h
index 57c572af3defd..4141e1434f72f 100644
--- a/clang/lib/Format/FormatTokenLexer.h
+++ b/clang/lib/Format/FormatTokenLexer.h
@@ -56,7 +56,6 @@ class FormatTokenLexer {
bool tryMergeNullishCoalescingEqual();
bool tryTransformCSharpForEach();
bool tryMergeForEach();
- bool tryTransformTryUsageForC();
// Merge the most recently lexed tokens into a single token if their kinds are
// correct.
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 4be9b3ea42930..db01af9593b1a 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -5008,9 +5008,11 @@ TEST_F(FormatTest, FormatTryCatch) {
}
TEST_F(FormatTest, FormatTryAsAVariable) {
- verifyFormat("int try;");
- verifyFormat("int try, size;");
- verifyFormat("try = foo();");
+ auto Style = getLLVMStyle(FormatStyle::LK_C);
+ verifyFormat("int try;", Style);
+ verifyFormat("int try, size;", Style);
+ verifyFormat("try = foo();", Style);
+
verifyFormat("if (try < size) {\n return true;\n}");
verifyFormat("int catch;");
@@ -5018,7 +5020,7 @@ TEST_F(FormatTest, FormatTryAsAVariable) {
verifyFormat("catch = foo();");
verifyFormat("if (catch < size) {\n return true;\n}");
- FormatStyle Style = getLLVMStyle();
+ Style.Language = FormatStyle::LK_Cpp;
Style.BreakBeforeBraces = FormatStyle::BS_Custom;
Style.BraceWrapping.AfterFunction = true;
Style.BraceWrapping.BeforeCatch = true;
More information about the cfe-commits
mailing list