[llvm-branch-commits] [clang] release/21.x: [clang-format] Fix an assertion failure on comment-only config files (#163111) (PR #163919)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Oct 16 23:48:13 PDT 2025
https://github.com/llvmbot created https://github.com/llvm/llvm-project/pull/163919
Backport d7921de8027eec19a9d272bf445944973e6758b1 059f2df74898ff7f394dc8e60f746323499ae32b
Requested by: @owenca
>From a30385efc12acbe53a040a327600349d7d6ac04b Mon Sep 17 00:00:00 2001
From: owenca <owenpiano at gmail.com>
Date: Thu, 25 Sep 2025 00:44:33 -0700
Subject: [PATCH 1/2] [clang-format] Correctly handle backward compatibility of
C headers (#159908)
This in effect reverts 05fb8408de23c3ccb6125b6886742177755bd757 and
7e1a88b9d1431e263258e3ff0f729c1fdce342d3, the latter of which
erroneously changed the behavior of formatting `ObjC` header files when
both the default and `ObjC` styles were absent. Now the previous
behavior of treating that as an error is restored.
Fixes #158704
(cherry picked from commit d7921de8027eec19a9d272bf445944973e6758b1)
---
clang/lib/Format/Format.cpp | 91 +++++++++++++---------
clang/unittests/Format/ConfigParseTest.cpp | 9 ++-
2 files changed, 59 insertions(+), 41 deletions(-)
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 161a6c4b47e7f..d4e3a1989cd71 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -2133,47 +2133,68 @@ std::error_code parseConfiguration(llvm::MemoryBufferRef Config,
if (Input.error())
return Input.error();
- for (unsigned i = 0; i < Styles.size(); ++i) {
- // Ensures that only the first configuration can skip the Language option.
- if (Styles[i].Language == FormatStyle::LK_None && i != 0)
+ assert(!Styles.empty());
+ const auto StyleCount = Styles.size();
+
+ // Start from the second style as (only) the first one may be the default.
+ for (unsigned I = 1; I < StyleCount; ++I) {
+ const auto Lang = Styles[I].Language;
+ if (Lang == FormatStyle::LK_None)
return make_error_code(ParseError::Error);
// Ensure that each language is configured at most once.
- for (unsigned j = 0; j < i; ++j) {
- if (Styles[i].Language == Styles[j].Language) {
+ for (unsigned J = 0; J < I; ++J) {
+ if (Lang == Styles[J].Language) {
LLVM_DEBUG(llvm::dbgs()
<< "Duplicate languages in the config file on positions "
- << j << " and " << i << "\n");
+ << J << " and " << I << '\n');
return make_error_code(ParseError::Error);
}
}
}
- // Look for a suitable configuration starting from the end, so we can
- // find the configuration for the specific language first, and the default
- // configuration (which can only be at slot 0) after it.
- FormatStyle::FormatStyleSet StyleSet;
- bool LanguageFound = false;
- for (const FormatStyle &Style : llvm::reverse(Styles)) {
- const auto Lang = Style.Language;
- if (Lang != FormatStyle::LK_None)
- StyleSet.Add(Style);
- if (Lang == Language ||
- // For backward compatibility.
- (Lang == FormatStyle::LK_Cpp && Language == FormatStyle::LK_C)) {
- LanguageFound = true;
- } else if (IsDotHFile && Language == FormatStyle::LK_Cpp &&
- (Lang == FormatStyle::LK_C || Lang == FormatStyle::LK_ObjC)) {
- Language = Lang;
- LanguageFound = true;
+
+ int LanguagePos = -1; // Position of the style for Language.
+ int CppPos = -1; // Position of the style for C++.
+ int CPos = -1; // Position of the style for C.
+
+ // Search Styles for Language and store the positions of C++ and C styles in
+ // case Language is not found.
+ for (unsigned I = 0; I < StyleCount; ++I) {
+ const auto Lang = Styles[I].Language;
+ if (Lang == Language) {
+ LanguagePos = I;
+ break;
}
- }
- if (!LanguageFound) {
- if (Styles.empty() || Styles[0].Language != FormatStyle::LK_None)
+ if (Lang == FormatStyle::LK_Cpp)
+ CppPos = I;
+ else if (Lang == FormatStyle::LK_C)
+ CPos = I;
+ }
+
+ // If Language is not found, use the default style if there is one. Otherwise,
+ // use the C style for C++ .h files and for backward compatibility, the C++
+ // style for .c files.
+ if (LanguagePos < 0) {
+ if (Styles[0].Language == FormatStyle::LK_None) // Default style.
+ LanguagePos = 0;
+ else if (IsDotHFile && Language == FormatStyle::LK_Cpp)
+ LanguagePos = CPos;
+ else if (!IsDotHFile && Language == FormatStyle::LK_C)
+ LanguagePos = CppPos;
+ if (LanguagePos < 0)
return make_error_code(ParseError::Unsuitable);
- FormatStyle DefaultStyle = Styles[0];
- DefaultStyle.Language = Language;
- StyleSet.Add(std::move(DefaultStyle));
}
- *Style = *StyleSet.Get(Language);
+
+ for (const auto &S : llvm::reverse(llvm::drop_begin(Styles)))
+ Style->StyleSet.Add(S);
+
+ *Style = Styles[LanguagePos];
+
+ if (LanguagePos == 0) {
+ if (Style->Language == FormatStyle::LK_None) // Default style.
+ Style->Language = Language;
+ Style->StyleSet.Add(*Style);
+ }
+
if (Style->InsertTrailingCommas != FormatStyle::TCS_None &&
Style->BinPackArguments) {
// See comment on FormatStyle::TSC_Wrapped.
@@ -2204,14 +2225,8 @@ FormatStyle::FormatStyleSet::Get(FormatStyle::LanguageKind Language) const {
if (!Styles)
return std::nullopt;
auto It = Styles->find(Language);
- if (It == Styles->end()) {
- if (Language != FormatStyle::LK_C)
- return std::nullopt;
- // For backward compatibility.
- It = Styles->find(FormatStyle::LK_Cpp);
- if (It == Styles->end())
- return std::nullopt;
- }
+ if (It == Styles->end())
+ return std::nullopt;
FormatStyle Style = It->second;
Style.StyleSet = *this;
return Style;
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index 2b17c36f6aa84..bbe1923e19ee1 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -1269,7 +1269,7 @@ TEST(ConfigParseTest, AllowCppForC) {
ParseError::Success);
}
-TEST(ConfigParseTest, HandleNonCppDotHFile) {
+TEST(ConfigParseTest, HandleDotHFile) {
FormatStyle Style = {};
Style.Language = FormatStyle::LK_Cpp;
EXPECT_EQ(parseConfiguration("Language: C", &Style,
@@ -1280,11 +1280,14 @@ TEST(ConfigParseTest, HandleNonCppDotHFile) {
Style = {};
Style.Language = FormatStyle::LK_Cpp;
- EXPECT_EQ(parseConfiguration("Language: ObjC", &Style,
+ EXPECT_EQ(parseConfiguration("Language: Cpp\n"
+ "...\n"
+ "Language: C",
+ &Style,
/*AllowUnknownOptions=*/false,
/*IsDotHFile=*/true),
ParseError::Success);
- EXPECT_EQ(Style.Language, FormatStyle::LK_ObjC);
+ EXPECT_EQ(Style.Language, FormatStyle::LK_Cpp);
}
TEST(ConfigParseTest, UsesLanguageForBasedOnStyle) {
>From 61cd0a0125d08e3352833250c23706d68f06582d Mon Sep 17 00:00:00 2001
From: owenca <owenpiano at gmail.com>
Date: Thu, 16 Oct 2025 21:40:59 -0700
Subject: [PATCH 2/2] [clang-format] Fix an assertion failure on comment-only
config files (#163111)
(cherry picked from commit 059f2df74898ff7f394dc8e60f746323499ae32b)
---
clang/lib/Format/Format.cpp | 3 ++-
clang/unittests/Format/ConfigParseTest.cpp | 7 +++++++
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index d4e3a1989cd71..5bdb810a3925b 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -2132,8 +2132,9 @@ std::error_code parseConfiguration(llvm::MemoryBufferRef Config,
Input >> Styles;
if (Input.error())
return Input.error();
+ if (Styles.empty())
+ return make_error_code(ParseError::Success);
- assert(!Styles.empty());
const auto StyleCount = Styles.size();
// Start from the second style as (only) the first one may be the default.
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index bbe1923e19ee1..ff42f09b90cf3 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -1249,6 +1249,13 @@ TEST(ConfigParseTest, ParsesConfigurationWithLanguages) {
IndentWidth, 56u);
}
+TEST(ConfigParseTest, AllowCommentOnlyConfigFile) {
+ FormatStyle Style = {};
+ Style.Language = FormatStyle::LK_Cpp;
+ EXPECT_EQ(parseConfiguration("#Language: C", &Style), ParseError::Success);
+ EXPECT_EQ(Style.Language, FormatStyle::LK_Cpp);
+}
+
TEST(ConfigParseTest, AllowCppForC) {
FormatStyle Style = {};
Style.Language = FormatStyle::LK_C;
More information about the llvm-branch-commits
mailing list