[clang] [clang-format] Fix parsing of goto labels (PR #196815)
Björn Schäpers via cfe-commits
cfe-commits at lists.llvm.org
Sun May 10 09:02:58 PDT 2026
https://github.com/HazardyKnusperkeks created https://github.com/llvm/llvm-project/pull/196815
Goto labels are not the same as case labels, refering to the indentation of goto labels but also checking case label indentation on another line is quite confusing. Also just put the goto label on its own line.
Fixes #196662.
>From 4e7df7953122197c32f578ae40ca944e4716b481 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Sch=C3=A4pers?= <bjoern at hazardy.de>
Date: Sun, 10 May 2026 18:01:54 +0200
Subject: [PATCH] [clang-format] Fix parsing of goto labels
Goto labels are not the same as case labels, refering to the indentation
of goto labels but also checking case label indentation on another line
is quite confusing. Also just put the goto label on its own line.
Fixes #196662.
---
clang/lib/Format/UnwrappedLineParser.cpp | 46 +++++++++++++-----------
clang/lib/Format/UnwrappedLineParser.h | 3 +-
clang/unittests/Format/FormatTest.cpp | 19 ++++++++++
3 files changed, 45 insertions(+), 23 deletions(-)
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index 022fd62ed2bfc..85542fcafca93 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -1554,13 +1554,13 @@ void UnwrappedLineParser::parseStructuralElement(
nextToken();
if (FormatTok->is(tok::colon)) {
FormatTok->setFinalizedType(TT_CaseLabelColon);
- parseLabel();
+ parseCaseLabel();
return;
}
if (FormatTok->is(tok::arrow)) {
FormatTok->setFinalizedType(TT_CaseLabelArrow);
Default->setFinalizedType(TT_SwitchExpressionLabel);
- parseLabel();
+ parseCaseLabel();
return;
}
// e.g. "default void f() {}" in a Java interface.
@@ -1582,7 +1582,7 @@ void UnwrappedLineParser::parseStructuralElement(
nextToken();
break;
}
- parseCaseLabel();
+ parseCase();
return;
case tok::kw_goto:
nextToken();
@@ -1716,7 +1716,22 @@ void UnwrappedLineParser::parseStructuralElement(
if (!Line->InMacroBody || CurrentLines->size() > 1)
Line->Tokens.begin()->Tok->MustBreakBefore = true;
FormatTok->setFinalizedType(TT_GotoLabelColon);
- parseLabel(Style.IndentGotoLabels);
+ const auto OldLineLevel = Line->Level;
+ switch (Style.IndentGotoLabels) {
+ case FormatStyle::IGLS_NoIndent:
+ Line->Level = 0;
+ break;
+ case FormatStyle::IGLS_OuterIndent:
+ if (Line->Level > 1 || (!Line->InPPDirective && Line->Level > 0))
+ --Line->Level;
+ break;
+ case FormatStyle::IGLS_HalfIndent:
+ case FormatStyle::IGLS_InnerIndent:
+ break;
+ }
+ nextToken();
+ addUnwrappedLine();
+ Line->Level = OldLineLevel;
if (HasLabel)
*HasLabel = true;
return;
@@ -2151,7 +2166,7 @@ void UnwrappedLineParser::parseStructuralElement(
nextToken();
break;
}
- parseCaseLabel();
+ parseCase();
break;
case tok::kw_default:
nextToken();
@@ -3374,23 +3389,12 @@ void UnwrappedLineParser::parseDoWhile() {
parseStructuralElement();
}
-void UnwrappedLineParser::parseLabel(
- FormatStyle::IndentGotoLabelStyle IndentGotoLabels) {
+void UnwrappedLineParser::parseCaseLabel() {
nextToken();
unsigned OldLineLevel = Line->Level;
- switch (IndentGotoLabels) {
- case FormatStyle::IGLS_NoIndent:
- Line->Level = 0;
- break;
- case FormatStyle::IGLS_OuterIndent:
- if (Line->Level > 1 || (!Line->InPPDirective && Line->Level > 0))
- --Line->Level;
- break;
- case FormatStyle::IGLS_HalfIndent:
- case FormatStyle::IGLS_InnerIndent:
- break;
- }
+ if (Line->Level > 1 || (!Line->InPPDirective && Line->Level > 0))
+ --Line->Level;
if (!Style.IndentCaseBlocks && CommentsBeforeNextToken.empty() &&
FormatTok->is(tok::l_brace)) {
@@ -3423,7 +3427,7 @@ void UnwrappedLineParser::parseLabel(
}
}
-void UnwrappedLineParser::parseCaseLabel() {
+void UnwrappedLineParser::parseCase() {
assert(FormatTok->is(tok::kw_case) && "'case' expected");
auto *Case = FormatTok;
@@ -3440,7 +3444,7 @@ void UnwrappedLineParser::parseCaseLabel() {
break;
}
} while (!eof());
- parseLabel();
+ parseCaseLabel();
}
void UnwrappedLineParser::parseSwitch(bool IsExpr) {
diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h
index 8181eec1495f7..cc7be26c2fc5b 100644
--- a/clang/lib/Format/UnwrappedLineParser.h
+++ b/clang/lib/Format/UnwrappedLineParser.h
@@ -159,9 +159,8 @@ class UnwrappedLineParser {
void parseLoopBody(bool KeepBraces, bool WrapRightBrace);
void parseForOrWhileLoop(bool HasParens = true);
void parseDoWhile();
- void parseLabel(FormatStyle::IndentGotoLabelStyle IndentGotoLabels =
- FormatStyle::IGLS_OuterIndent);
void parseCaseLabel();
+ void parseCase();
void parseSwitch(bool IsExpr);
void parseNamespace();
bool parseModuleImport();
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 4245bd1c58153..5a963cf7f36ea 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -3168,6 +3168,25 @@ TEST_F(FormatTest, FormatsLabels) {
" g();\n"
" }\n"
"}");
+ verifyFormat("void func() {\n"
+ "label:\n"
+ " {\n"
+ " // Block\n"
+ " }\n"
+ "}");
+ verifyFormat("void func() {\n"
+ "label: // Comment\n"
+ " {\n"
+ " // Block\n"
+ " }\n"
+ "}");
+ verifyFormat("void func() {\n"
+ "label:\n"
+ " // Comment\n"
+ " {\n"
+ " // Block\n"
+ " }\n"
+ "}");
FormatStyle Style = getLLVMStyle();
Style.IndentGotoLabels = FormatStyle::IGLS_NoIndent;
More information about the cfe-commits
mailing list