Skip to content

Conversation

@kikairoya
Copy link
Contributor

Cygwin builds are currently broken after #157312, which effectively reverted #138117. The root cause is that Cygwin defines DL_info::dli_fname as char[N], which is not a valid parameter type for llvm::format.

This patch allows llvm::format to accept char[N] by decaying it to const char *. As a result, string literals are also accepted without an explicit cast.

Other array types remain rejected:

  • Wide/unicode character arrays (e.g., wchar_t[N]) are not supported, as LLVM does not use them and they are less compatible with platform's printf implementations.
  • Non-character arrays (e.g., int[N]) are also rejected, since passing such arrays to printf is meaningless.

@llvmbot
Copy link
Member

llvmbot commented Sep 18, 2025

@llvm/pr-subscribers-llvm-support

Author: Tomohiro Kashiwada (kikairoya)

Changes

Cygwin builds are currently broken after #157312, which effectively reverted #138117. The root cause is that Cygwin defines DL_info::dli_fname as char[N], which is not a valid parameter type for llvm::format.

This patch allows llvm::format to accept char[N] by decaying it to const char *. As a result, string literals are also accepted without an explicit cast.

Other array types remain rejected:

  • Wide/unicode character arrays (e.g., wchar_t[N]) are not supported, as LLVM does not use them and they are less compatible with platform's printf implementations.
  • Non-character arrays (e.g., int[N]) are also rejected, since passing such arrays to printf is meaningless.

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

3 Files Affected:

  • (modified) llvm/include/llvm/Support/Format.h (+14-2)
  • (modified) llvm/unittests/Support/CMakeLists.txt (+1)
  • (added) llvm/unittests/Support/Format.cpp (+56)
diff --git a/llvm/include/llvm/Support/Format.h b/llvm/include/llvm/Support/Format.h
index 2553002b37899..6cd73a213177d 100644
--- a/llvm/include/llvm/Support/Format.h
+++ b/llvm/include/llvm/Support/Format.h
@@ -78,6 +78,7 @@ class LLVM_ABI format_object_base {
 /// printed, this synthesizes the string into a temporary buffer provided and
 /// returns whether or not it is big enough.
 
+namespace detail {
 // Helper to validate that format() parameters are scalars or pointers.
 template <typename... Args> struct validate_format_parameters;
 template <typename Arg, typename... Args>
@@ -88,9 +89,19 @@ struct validate_format_parameters<Arg, Args...> {
 };
 template <> struct validate_format_parameters<> {};
 
+template <typename T> struct decay_if_c_char_array {
+  using type = T;
+};
+template <std::size_t N> struct decay_if_c_char_array<char[N]> {
+  using type = const char *;
+};
+template <typename T>
+using decay_if_c_char_array_t = typename decay_if_c_char_array<T>::type;
+} // namespace detail
+
 template <typename... Ts>
 class format_object final : public format_object_base {
-  std::tuple<Ts...> Vals;
+  std::tuple<detail::decay_if_c_char_array_t<Ts>...> Vals;
 
   template <std::size_t... Is>
   int snprint_tuple(char *Buffer, unsigned BufferSize,
@@ -105,7 +116,8 @@ class format_object final : public format_object_base {
 public:
   format_object(const char *fmt, const Ts &... vals)
       : format_object_base(fmt), Vals(vals...) {
-    validate_format_parameters<Ts...>();
+    detail::validate_format_parameters<
+        detail::decay_if_c_char_array_t<Ts>...>();
   }
 
   int snprint(char *Buffer, unsigned BufferSize) const override {
diff --git a/llvm/unittests/Support/CMakeLists.txt b/llvm/unittests/Support/CMakeLists.txt
index d1dfb1dc4a722..1f2a68545d107 100644
--- a/llvm/unittests/Support/CMakeLists.txt
+++ b/llvm/unittests/Support/CMakeLists.txt
@@ -44,6 +44,7 @@ add_llvm_unittest(SupportTests
   ExtensibleRTTITest.cpp
   FileCollectorTest.cpp
   FileOutputBufferTest.cpp
+  Format.cpp
   FormatVariadicTest.cpp
   FSUniqueIDTest.cpp
   GenericDomTreeTest.cpp
diff --git a/llvm/unittests/Support/Format.cpp b/llvm/unittests/Support/Format.cpp
new file mode 100644
index 0000000000000..c4e421fe9dc4c
--- /dev/null
+++ b/llvm/unittests/Support/Format.cpp
@@ -0,0 +1,56 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Format.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+template <typename FormatTy>
+std::string printToString(unsigned MaxN, FormatTy &&Fmt) {
+  std::vector<char> Dst(MaxN + 2);
+  int N = Fmt.snprint(Dst.data(), Dst.size());
+  Dst.back() = 0;
+  return N < 0 ? "" : Dst.data();
+}
+
+template <typename Expected, typename Arg>
+constexpr bool checkDecayTypeEq(const Arg &arg) {
+  return std::is_same_v<detail::decay_if_c_char_array_t<Arg>, Expected>;
+}
+
+TEST(Format, DecayIfCCharArray) {
+  char Array[] = "Array";
+  const char ConstArray[] = "ConstArray";
+  char PtrBuf[] = "Ptr";
+  char *Ptr = PtrBuf;
+  const char *PtrToConst = "PtrToConst";
+
+  EXPECT_EQ("        Literal", printToString(20, format("%15s", "Literal")));
+  EXPECT_EQ("          Array", printToString(20, format("%15s", Array)));
+  EXPECT_EQ("     ConstArray", printToString(20, format("%15s", ConstArray)));
+  EXPECT_EQ("            Ptr", printToString(20, format("%15s", Ptr)));
+  EXPECT_EQ("     PtrToConst", printToString(20, format("%15s", PtrToConst)));
+
+  EXPECT_TRUE(checkDecayTypeEq<const char *>("Literal"));
+  EXPECT_TRUE(checkDecayTypeEq<const char *>(Array));
+  EXPECT_TRUE(checkDecayTypeEq<const char *>(ConstArray));
+  EXPECT_TRUE(checkDecayTypeEq<char *>(Ptr));
+  EXPECT_TRUE(checkDecayTypeEq<const char *>(PtrToConst));
+  EXPECT_TRUE(checkDecayTypeEq<char>(PtrToConst[0]));
+  EXPECT_TRUE(
+      checkDecayTypeEq<const char *>(static_cast<const char *>("Literal")));
+
+  wchar_t WCharArray[] = L"WCharArray";
+  EXPECT_TRUE(checkDecayTypeEq<wchar_t[11]>(WCharArray));
+  EXPECT_TRUE(checkDecayTypeEq<wchar_t>(WCharArray[0]));
+}
+
+} // namespace

@kikairoya
Copy link
Contributor Author

ping

Cygwin builds are currently broken after llvm#157312, which effectively reverted llvm#138117.
The root cause is that Cygwin defines `DL_info::dli_fname` as `char[N]`, which
is not a valid parameter type for `llvm::format`.

This patch allows `llvm::format` to accept `char[N]` by decaying it to
`const char *`. As a result, string literals are also accepted without an
explicit cast.

Other array types remain rejected:
- Wide/unicode character arrays (e.g., `wchar_t[N]`) are not supported, as LLVM
  does not use them and they are less compatible with platform's `printf` implementations.
- Non-character arrays (e.g., `int[N]`) are also rejected, since passing such
  arrays to `printf` is meaningless.
@kikairoya kikairoya force-pushed the format-allow-ref-to-array branch from f5d7184 to f74084c Compare October 2, 2025 10:09
@kikairoya
Copy link
Contributor Author

ping

@kikairoya
Copy link
Contributor Author

ping.

@kazutakahirata @tgymnich Could you please take a look at this?

Copy link
Contributor

@kazutakahirata kazutakahirata left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the breakage and delay in reviewing this.

LGTM. Thanks!

@tgymnich tgymnich merged commit ea25153 into llvm:main Oct 13, 2025
9 checks passed
@kikairoya
Copy link
Contributor Author

Thank you for the reviewing and merging this!

@kikairoya kikairoya deleted the format-allow-ref-to-array branch October 13, 2025 09:11
DharuniRAcharya pushed a commit to DharuniRAcharya/llvm-project that referenced this pull request Oct 13, 2025
…9541)

Cygwin builds are currently broken after llvm#157312, which effectively
reverted llvm#138117. The root cause is that Cygwin defines
`DL_info::dli_fname` as `char[N]`, which is not a valid parameter type
for `llvm::format`.

This patch allows `llvm::format` to accept `char[N]` by decaying it to
`const char *`. As a result, string literals are also accepted without
an explicit cast.

Other array types remain rejected:
- Wide/unicode character arrays (e.g., `wchar_t[N]`) are not supported,
as LLVM does not use them and they are less compatible with platform's
`printf` implementations.
- Non-character arrays (e.g., `int[N]`) are also rejected, since passing
such arrays to `printf` is meaningless.
@llvm-ci
Copy link
Collaborator

llvm-ci commented Oct 13, 2025

LLVM Buildbot has detected a new failure on builder ppc64le-lld-multistage-test running on ppc64le-lld-multistage-test while building llvm at step 7 "test-build-stage1-unified-tree-check-all".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/168/builds/16618

Here is the relevant piece of the build log for the reference
Step 7 (test-build-stage1-unified-tree-check-all) failure: 1200 seconds without output running [b'ninja', b'check-all'], attempting to kill
...
llvm-lit: /home/buildbots/llvm-external-buildbots/workers/ppc64le-lld-multistage-test/ppc64le-lld-multistage-test/llvm-project/llvm/utils/lit/lit/llvm/config.py:531: note: using ld.lld: /home/buildbots/llvm-external-buildbots/workers/ppc64le-lld-multistage-test/ppc64le-lld-multistage-test/build/stage1/bin/ld.lld
llvm-lit: /home/buildbots/llvm-external-buildbots/workers/ppc64le-lld-multistage-test/ppc64le-lld-multistage-test/llvm-project/llvm/utils/lit/lit/llvm/config.py:531: note: using lld-link: /home/buildbots/llvm-external-buildbots/workers/ppc64le-lld-multistage-test/ppc64le-lld-multistage-test/build/stage1/bin/lld-link
llvm-lit: /home/buildbots/llvm-external-buildbots/workers/ppc64le-lld-multistage-test/ppc64le-lld-multistage-test/llvm-project/llvm/utils/lit/lit/llvm/config.py:531: note: using ld64.lld: /home/buildbots/llvm-external-buildbots/workers/ppc64le-lld-multistage-test/ppc64le-lld-multistage-test/build/stage1/bin/ld64.lld
llvm-lit: /home/buildbots/llvm-external-buildbots/workers/ppc64le-lld-multistage-test/ppc64le-lld-multistage-test/llvm-project/llvm/utils/lit/lit/llvm/config.py:531: note: using wasm-ld: /home/buildbots/llvm-external-buildbots/workers/ppc64le-lld-multistage-test/ppc64le-lld-multistage-test/build/stage1/bin/wasm-ld
llvm-lit: /home/buildbots/llvm-external-buildbots/workers/ppc64le-lld-multistage-test/ppc64le-lld-multistage-test/build/stage1/utils/lit/tests/lit.cfg:111: warning: Setting a timeout per test not supported. Requires the Python psutil module but it could not be found. Try installing it via pip or via your operating system's package manager.
 Some tests will be skipped and the --timeout command line argument will not work.
llvm-lit: /home/buildbots/llvm-external-buildbots/workers/ppc64le-lld-multistage-test/ppc64le-lld-multistage-test/llvm-project/llvm/utils/lit/lit/llvm/config.py:531: note: using ld.lld: /home/buildbots/llvm-external-buildbots/workers/ppc64le-lld-multistage-test/ppc64le-lld-multistage-test/build/stage1/bin/ld.lld
llvm-lit: /home/buildbots/llvm-external-buildbots/workers/ppc64le-lld-multistage-test/ppc64le-lld-multistage-test/llvm-project/llvm/utils/lit/lit/llvm/config.py:531: note: using lld-link: /home/buildbots/llvm-external-buildbots/workers/ppc64le-lld-multistage-test/ppc64le-lld-multistage-test/build/stage1/bin/lld-link
llvm-lit: /home/buildbots/llvm-external-buildbots/workers/ppc64le-lld-multistage-test/ppc64le-lld-multistage-test/llvm-project/llvm/utils/lit/lit/llvm/config.py:531: note: using ld64.lld: /home/buildbots/llvm-external-buildbots/workers/ppc64le-lld-multistage-test/ppc64le-lld-multistage-test/build/stage1/bin/ld64.lld
llvm-lit: /home/buildbots/llvm-external-buildbots/workers/ppc64le-lld-multistage-test/ppc64le-lld-multistage-test/llvm-project/llvm/utils/lit/lit/llvm/config.py:531: note: using wasm-ld: /home/buildbots/llvm-external-buildbots/workers/ppc64le-lld-multistage-test/ppc64le-lld-multistage-test/build/stage1/bin/wasm-ld
command timed out: 1200 seconds without output running [b'ninja', b'check-all'], attempting to kill
process killed by signal 9
program finished with exit code -1
elapsedTime=3240.738954
Testing:  0.. 10.. 20.. 30
Step 9 (clean-build/stage2-dir) failure: Delete failed. (failure) (timed out)

akadutta pushed a commit to akadutta/llvm-project that referenced this pull request Oct 14, 2025
…9541)

Cygwin builds are currently broken after llvm#157312, which effectively
reverted llvm#138117. The root cause is that Cygwin defines
`DL_info::dli_fname` as `char[N]`, which is not a valid parameter type
for `llvm::format`.

This patch allows `llvm::format` to accept `char[N]` by decaying it to
`const char *`. As a result, string literals are also accepted without
an explicit cast.

Other array types remain rejected:
- Wide/unicode character arrays (e.g., `wchar_t[N]`) are not supported,
as LLVM does not use them and they are less compatible with platform's
`printf` implementations.
- Non-character arrays (e.g., `int[N]`) are also rejected, since passing
such arrays to `printf` is meaningless.
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.

6 participants