Skip to content

[Support] Add format object for interleaved ranges #135517

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 16, 2025

Conversation

kuhar
Copy link
Member

@kuhar kuhar commented Apr 13, 2025

Add two new format functions for printing ranges: interleaved and interleaved_array.

This is meant to improve the ergonomics of printing ranges. Before this patch, we have to either use llvm::interleave or write a for loop by hand. For example:

Before:

ArrayRef<Type> types = ...;
ArrayRef<Values> values = ...;
LLVM_DEBUG({
  llvm::dbgs() << "Types: ";
  llvm::interleave_comma(llvm::dbgs(), types);
  llvm::dbgs() << "\n";
  llvm::dbgs() << "Values: [";
  llvm::interleave_comma(llvm::dbgs(), values);
  llvm::dbgs() << "]\n";
}):

After:

ArrayRef<Type> types = ...;
ArrayRef<Values> values = ...;
LLVM_DEBUG(llvm::dbgs() << "Types: " << interleaved(types) << "\n");
LLVM_DEBUG(llvm::dbgs() << "Values: " << interleaved_array(values) << "\n");

The separator and the prefix/suffix strings are customizable.

@llvmbot
Copy link
Member

llvmbot commented Apr 13, 2025

@llvm/pr-subscribers-llvm-support

Author: Jakub Kuderski (kuhar)

Changes

Add two new format functions for printing ranges: interleaved and interleaved_array.

This is meant to improve the ergonomics of printing ranges. Before this patch, we have to either use llvm::interleave or write a for loop by hand. For example:

Before:

ArrayRef&lt;Type&gt; types = ...;
ArrayRef&lt;Values&gt; values = ...;
LLVM_DEBUG({
  llvm::dbgs() &lt;&lt; "Types: ";
  llvm::interleave_comma(llvm::dbgs(), types);
  llvm::dbgs() &lt;&lt; "\n";
  llvm::dbgs() &lt;&lt; "Values: [";
  llvm::interleave_comma(llvm::dbgs(), values);
  llvm::dbgs() &lt;&lt; "]\n";
}):

After:

ArrayRef&lt;Type&gt; types = ...;
ArrayRef&lt;Values&gt; values = ...;
LLVM_DEBUG(llvm::dbgs() &lt;&lt; "Types: " &lt;&lt; interleaved(types) &lt;&lt; "\n");
LLVM_DEBUG(llvm::dbgs() &lt;&lt; "Values: " &lt;&lt; interleaved_array(values) &lt;&lt; "\n");

The separator and the prefix/suffix strings are customizable.


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

5 Files Affected:

  • (modified) llvm/include/llvm/Support/Format.h (+85)
  • (modified) llvm/include/llvm/Support/raw_ostream.h (+5-1)
  • (modified) llvm/lib/Support/raw_ostream.cpp (+10-2)
  • (modified) llvm/unittests/Support/CMakeLists.txt (+2-1)
  • (added) llvm/unittests/Support/InterleavedRangeTest.cpp (+70)
diff --git a/llvm/include/llvm/Support/Format.h b/llvm/include/llvm/Support/Format.h
index 89b6ae35ba5de..f6c6e449aae6b 100644
--- a/llvm/include/llvm/Support/Format.h
+++ b/llvm/include/llvm/Support/Format.h
@@ -26,6 +26,7 @@
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/DataTypes.h"
+#include "llvm/Support/raw_ostream.h"
 #include <cassert>
 #include <cstdio>
 #include <optional>
@@ -255,6 +256,90 @@ format_bytes_with_ascii(ArrayRef<uint8_t> Bytes,
                         ByteGroupSize, Upper, true);
 }
 
+/// The base class for printing interleaved ranges. Provides a virtual function
+/// to be used by the '<<' operator in raw_ostream. This class is not intended
+/// to be copied or used in polymorphic containers.
+class InterleavedRangeBase {
+protected:
+  ~InterleavedRangeBase() = default; // Disallow polymorphic deletion.
+  InterleavedRangeBase() = default;
+  InterleavedRangeBase(const InterleavedRangeBase &) = delete; // Disallow copy.
+  virtual void home(); // Out of line virtual method to anchor the vtable.
+
+  /// Appends the interleaved range to the output stream `OS`.
+  virtual void printInterleaved(raw_ostream &OS) const = 0;
+
+  friend class raw_ostream;
+};
+
+/// The concrete class template for interleaved ranges. Supports specifying the
+/// separator and, optionally, the prefix and suffix to be printed surrounding
+/// the range.
+/// Uses the operator '<<' of the range element type for printing. The range
+/// type itself does not have to have an '<<' operator defined.
+template <typename Range>
+class InterleavedRange final : public InterleavedRangeBase {
+  const Range &TheRange;
+  StringRef Separator;
+  StringRef Prefix;
+  StringRef Suffix;
+
+  virtual void printInterleaved(raw_ostream &OS) const override {
+    if (!Prefix.empty())
+      OS << Prefix;
+    llvm::interleave(TheRange, OS, Separator);
+    if (!Suffix.empty())
+      OS << Suffix;
+  }
+
+public:
+  InterleavedRange(const Range &R, StringRef Separator, StringRef Prefix,
+                   StringRef Suffix)
+      : TheRange(R), Separator(Separator), Prefix(Prefix), Suffix(Suffix) {}
+
+  std::string str() const {
+    std::string Result;
+    raw_string_ostream Stream(Result);
+    Stream << *this;
+    Stream.flush();
+    return Result;
+  }
+
+  operator std::string() const { return str(); }
+};
+
+/// interleaved - Output range \p R as a sequence of interleaved elements.
+/// Requires the range element type to be printable using
+/// `raw_ostream& operator<<`. The \p Separator and \p Prefix / \p Suffix can be
+/// customized. Examples:
+/// ```c++
+///   SmallVector<int> Vals = {1, 2, 3};
+///   OS << interleaved(Vals);                 // ==> "1, 2, 3"
+///   OS << interleaved(Vals, ";");            // ==> "1;2;3"
+///   OS << interleaved(Vals, " ", "{", "}");  // ==> "{1 2 3}"
+/// ```
+template <typename Range>
+InterleavedRange<Range> interleaved(const Range &R, StringRef Separator = ", ",
+                                    StringRef Prefix = "",
+                                    StringRef Suffix = "") {
+  return {R, Separator, Prefix, Suffix};
+}
+
+/// interleaved - Output range \p R as an array of interleaved elements.
+/// Requires the range element type to be printable using
+/// `raw_ostream& operator<<`. The \p Separator can be customized. Examples:
+/// ```c++
+///   SmallVector<int> Vals = {1, 2, 3};
+///   OS << interleaved_array(Vals);       // ==> "[1, 2, 3]"
+///   OS << interleaved_array(Vals, ";");  // ==> "[1;2;3]"
+///   OS << interleaved_array(Vals, " ");  // ==> "[1 2 3]"
+/// ```
+template <typename Range>
+InterleavedRange<Range> interleaved_array(const Range &R,
+                                          StringRef Separator = ", ") {
+  return {R, Separator, "[", "]"};
+}
+
 } // end namespace llvm
 
 #endif
diff --git a/llvm/include/llvm/Support/raw_ostream.h b/llvm/include/llvm/Support/raw_ostream.h
index d3b411590e7fd..f6b2268a94927 100644
--- a/llvm/include/llvm/Support/raw_ostream.h
+++ b/llvm/include/llvm/Support/raw_ostream.h
@@ -29,12 +29,13 @@
 namespace llvm {
 
 class Duration;
+template <class T> class [[nodiscard]] Expected;
 class formatv_object_base;
 class format_object_base;
 class FormattedString;
 class FormattedNumber;
 class FormattedBytes;
-template <class T> class [[nodiscard]] Expected;
+class InterleavedRangeBase;
 
 namespace sys {
 namespace fs {
@@ -318,6 +319,9 @@ class raw_ostream {
   // Formatted output, see the format_bytes() function in Support/Format.h.
   raw_ostream &operator<<(const FormattedBytes &);
 
+  // Formatted output, see the interleaved() function in Support/Format.h.
+  raw_ostream &operator<<(const InterleavedRangeBase &);
+
   /// indent - Insert 'NumSpaces' spaces.
   raw_ostream &indent(unsigned NumSpaces);
 
diff --git a/llvm/lib/Support/raw_ostream.cpp b/llvm/lib/Support/raw_ostream.cpp
index e75ddc66b7d16..58d5568cdcea1 100644
--- a/llvm/lib/Support/raw_ostream.cpp
+++ b/llvm/lib/Support/raw_ostream.cpp
@@ -471,6 +471,12 @@ raw_ostream &raw_ostream::operator<<(const FormattedBytes &FB) {
   return *this;
 }
 
+raw_ostream &
+raw_ostream::operator<<(const InterleavedRangeBase &InterleavedRange) {
+  InterleavedRange.printInterleaved(*this);
+  return *this;
+}
+
 template <char C>
 static raw_ostream &write_padding(raw_ostream &OS, unsigned NumChars) {
   static const char Chars[] = {C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C,
@@ -555,8 +561,10 @@ void raw_ostream::anchor() {}
 //===----------------------------------------------------------------------===//
 
 // Out of line virtual method.
-void format_object_base::home() {
-}
+void format_object_base::home() {}
+
+// Out of line virtual method.
+void InterleavedRangeBase::home() {}
 
 //===----------------------------------------------------------------------===//
 //  raw_fd_ostream
diff --git a/llvm/unittests/Support/CMakeLists.txt b/llvm/unittests/Support/CMakeLists.txt
index 6c4e7cb689b20..4a12a928af119 100644
--- a/llvm/unittests/Support/CMakeLists.txt
+++ b/llvm/unittests/Support/CMakeLists.txt
@@ -49,6 +49,7 @@ add_llvm_unittest(SupportTests
   HashBuilderTest.cpp
   IndexedAccessorTest.cpp
   InstructionCostTest.cpp
+  InterleavedRangeTest.cpp
   JSONTest.cpp
   KnownBitsTest.cpp
   LEB128Test.cpp
@@ -61,7 +62,7 @@ add_llvm_unittest(SupportTests
   MemoryBufferRefTest.cpp
   MemoryBufferTest.cpp
   MemoryTest.cpp
-  MustacheTest.cpp      
+  MustacheTest.cpp
   ModRefTest.cpp
   NativeFormatTests.cpp
   OptimizedStructLayoutTest.cpp
diff --git a/llvm/unittests/Support/InterleavedRangeTest.cpp b/llvm/unittests/Support/InterleavedRangeTest.cpp
new file mode 100644
index 0000000000000..53acf36040b67
--- /dev/null
+++ b/llvm/unittests/Support/InterleavedRangeTest.cpp
@@ -0,0 +1,70 @@
+//===- InterleavedRangeTest.cpp - Unit tests for interleaved format -------===//
+//
+// 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 "llvm/ADT/SmallVector.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+TEST(InterleavedRangeTest, VectorInt) {
+  SmallVector<int> V = {0, 1, 2, 3};
+
+  // First, make sure that the raw print API works as expected.
+  std::string Buff;
+  raw_string_ostream OS(Buff);
+  OS << interleaved(V);
+  EXPECT_EQ("0, 1, 2, 3", Buff);
+  Buff.clear();
+  OS << interleaved_array(V);
+  EXPECT_EQ("[0, 1, 2, 3]", Buff);
+
+  // In the rest of the tests, use `.str()` for convenience.
+  EXPECT_EQ("0, 1, 2, 3", interleaved(V).str());
+  EXPECT_EQ("{{0,1,2,3}}", interleaved(V, ",", "{{", "}}").str());
+  EXPECT_EQ("[0, 1, 2, 3]", interleaved_array(V).str());
+  EXPECT_EQ("[0;1;2;3]", interleaved_array(V, ";").str());
+  EXPECT_EQ("0;1;2;3", interleaved(V, ";").str());
+}
+
+TEST(InterleavedRangeTest, VectorIntEmpty) {
+  SmallVector<int> V = {};
+  EXPECT_EQ("", interleaved(V).str());
+  EXPECT_EQ("{{}}", interleaved(V, ",", "{{", "}}").str());
+  EXPECT_EQ("[]", interleaved_array(V).str());
+  EXPECT_EQ("", interleaved(V, ";").str());
+}
+
+TEST(InterleavedRangeTest, VectorIntOneElem) {
+  SmallVector<int> V = {42};
+  EXPECT_EQ("42", interleaved(V).str());
+  EXPECT_EQ("{{42}}", interleaved(V, ",", "{{", "}}").str());
+  EXPECT_EQ("[42]", interleaved_array(V).str());
+  EXPECT_EQ("42", interleaved(V, ";").str());
+}
+
+struct CustomPrint {
+  int N;
+  friend raw_ostream &operator<<(raw_ostream &OS, const CustomPrint &CP) {
+    OS << "$$" << CP.N << "##";
+    return OS;
+  }
+};
+
+TEST(InterleavedRangeTest, CustomPrint) {
+  CustomPrint V[] = {{3}, {4}, {5}};
+  EXPECT_EQ("$$3##, $$4##, $$5##", interleaved(V).str());
+  EXPECT_EQ("{{$$3##;$$4##;$$5##}}", interleaved(V, ";", "{{", "}}").str());
+  EXPECT_EQ("[$$3##, $$4##, $$5##]", interleaved_array(V).str());
+}
+
+} // namespace

@kuhar kuhar requested a review from bjacob April 13, 2025 03:36
Copy link

github-actions bot commented Apr 13, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

Add two new format functions for printing ranges: `interleaved` and
`interleaved_array`.

This is meant to improve the ergonomics of printing ranges. Before this
patch, we have to either use `llvm::interleave` or write a for loop by
hand. For example:

Before:
```c++
ArrayRef<Type> types = ...;
ArrayRef<Values> values = ...;
LLVM_DEBUG({
  llvm::dbgs() << "Types: ";
  llvm::interleave_comma(llvm::dbgs(), types);
  llvm::dbgs() << "\n";
  llvm::dbgs() << "Values: [";
  llvm::interleave_comma(llvm::dbgs(), values);
  llvm::dbgs() << "]\n";
}):
```

After:
```
ArrayRef<Type> types = ...;
ArrayRef<Values> values = ...;
LLVM_DEBUG(llvm::dbgs() << "Types: " << interleaved(types) << "\n");
LLVM_DEBUG(llvm::dbgs() << "Values: " << interleaved_array(values) << "\n");
```

The separator and the preffix/suffix strings are customizable.
@kuhar kuhar force-pushed the format-interleaved branch from 13e4bdb to 32dcded Compare April 13, 2025 18:21
@dwblaikie
Copy link
Collaborator

Honestly interleave seems like the better name for this than interleaved... but I guess not a huge deal either way.

How would it look to migrate the existing uses of interleave to something like this instead fo introducing an alternative? (Probably have to do both so the migration isn't monolithic - but as a concept, is migrating a feasible/useful direction?)

@dwblaikie
Copy link
Collaborator

Oh, and any precedent for this in the standard library or boost, etc? So we can pick a similar name/interface at least?

@kuhar
Copy link
Member Author

kuhar commented Apr 15, 2025

Honestly interleave seems like the better name for this than interleaved... but I guess not a huge deal either way.

interleave is already taken unless we nest this in a new namespace.

How would it look to migrate the existing uses of interleave to something like this instead fo introducing an alternative? (Probably have to do both so the migration isn't monolithic - but as a concept, is migrating a feasible/useful direction?)

Yes, I want to migrate existing uses of interleave to this. We should be able to deprecate interleave eventually.

Oh, and any precedent for this in the standard library or boost, etc? So we can pick a similar name/interface at least?

Yes! This is inspired by https://en.cppreference.com/w/cpp/io/manip/quoted -- the naming is similar on purpose. I'm not aware of anything for ranges though.

return Result;
}

operator std::string() const { return str(); }
Copy link
Contributor

Choose a reason for hiding this comment

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

Just a question - do you want explicit here?

Copy link
Member Author

@kuhar kuhar Apr 15, 2025

Choose a reason for hiding this comment

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

llvm::formatv doesn't use explicit either and it seems to work fine. Do you see some footguns here? Because this is not a reference/handle/pointer type, I think it's OK.

template <typename Range>
InterleavedRange<Range> interleaved_array(const Range &R,
StringRef Separator = ", ") {
return {R, Separator, "[", "]"};
Copy link
Collaborator

Choose a reason for hiding this comment

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

It's probably a lost cause, but I don't /think/ we use {} to invoke ctors for types that aren't pretty struct-like (exposing their members publicly? some other aspects?), I'd have expected this to be return InterleavedRange(R, Separator, ...); at least, possibly with the <Range> in there too.

But... it's probably the case that there is more {} usage than I'd expect and unlikely to be clawed back in any way, so I'm not sure of the direction I'm suggesting/wouldn't feel strongly about sticking with this code as-is.

Copy link
Member Author

Choose a reason for hiding this comment

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

This pattern is not uncommon in llvm and I don't see anything against it in the coding standards doc, so I'm going to keep this as-is.

@kuhar kuhar merged commit b07c885 into llvm:main Apr 16, 2025
11 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Apr 16, 2025

LLVM Buildbot has detected a new failure on builder clang-cmake-x86_64-avx512-win running on avx512-intel64-win while building llvm at step 4 "cmake stage 1".

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

Here is the relevant piece of the build log for the reference
Step 4 (cmake stage 1) failure: 'cmake -G ...' (failure)
'cmake' is not recognized as an internal or external command,
operable program or batch file.

@llvm-ci
Copy link
Collaborator

llvm-ci commented Apr 16, 2025

LLVM Buildbot has detected a new failure on builder lld-x86_64-win running on as-worker-93 while building llvm at step 7 "test-build-unified-tree-check-all".

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

Here is the relevant piece of the build log for the reference
Step 7 (test-build-unified-tree-check-all) failure: test (failure)
******************** TEST 'LLVM-Unit :: Support/./SupportTests.exe/86/95' FAILED ********************
Script(shard):
--
GTEST_OUTPUT=json:C:\a\lld-x86_64-win\build\unittests\Support\.\SupportTests.exe-LLVM-Unit-24448-86-95.json GTEST_SHUFFLE=0 GTEST_TOTAL_SHARDS=95 GTEST_SHARD_INDEX=86 C:\a\lld-x86_64-win\build\unittests\Support\.\SupportTests.exe
--

Script:
--
C:\a\lld-x86_64-win\build\unittests\Support\.\SupportTests.exe --gtest_filter=ProgramEnvTest.CreateProcessLongPath
--
C:\a\lld-x86_64-win\llvm-project\llvm\unittests\Support\ProgramTest.cpp(160): error: Expected equality of these values:
  0
  RC
    Which is: -2

C:\a\lld-x86_64-win\llvm-project\llvm\unittests\Support\ProgramTest.cpp(163): error: fs::remove(Twine(LongPath)): did not return errc::success.
error number: 13
error message: permission denied



C:\a\lld-x86_64-win\llvm-project\llvm\unittests\Support\ProgramTest.cpp:160
Expected equality of these values:
  0
  RC
    Which is: -2

C:\a\lld-x86_64-win\llvm-project\llvm\unittests\Support\ProgramTest.cpp:163
fs::remove(Twine(LongPath)): did not return errc::success.
error number: 13
error message: permission denied




********************


@hanhanW
Copy link
Contributor

hanhanW commented Apr 16, 2025

Thanks for adding this. It is very useful for debugging and debug print. I'm already wanting to use it in IREE now. :)

var-const pushed a commit to ldionne/llvm-project that referenced this pull request Apr 17, 2025
Add two new format functions for printing ranges: `interleaved` and
`interleaved_array`.

This is meant to improve the ergonomics of printing ranges. Before this
patch, we have to either use `llvm::interleave` or write a for loop by
hand. For example:

Before:
```c++
ArrayRef<Type> types = ...;
ArrayRef<Values> values = ...;
LLVM_DEBUG({
  llvm::dbgs() << "Types: ";
  llvm::interleave_comma(llvm::dbgs(), types);
  llvm::dbgs() << "\n";
  llvm::dbgs() << "Values: [";
  llvm::interleave_comma(llvm::dbgs(), values);
  llvm::dbgs() << "]\n";
}):
```

After:
```c++
ArrayRef<Type> types = ...;
ArrayRef<Values> values = ...;
LLVM_DEBUG(llvm::dbgs() << "Types: " << interleaved(types) << "\n");
LLVM_DEBUG(llvm::dbgs() << "Values: " << interleaved_array(values) << "\n");
```

The separator and the prefix/suffix strings are customizable.
kuhar added a commit to kuhar/llvm-project that referenced this pull request Apr 18, 2025
Clean up printing code by switching to `llvm::interleaved` from
llvm#135517.
kuhar added a commit to kuhar/llvm-project that referenced this pull request Apr 18, 2025
Clean up printing code by switching to `llvm::interleaved` from
llvm#135517.
kuhar added a commit to kuhar/llvm-project that referenced this pull request Apr 18, 2025
Clean up printing code by switching to `llvm::interleaved` from
llvm#135517.
kuhar added a commit to kuhar/llvm-project that referenced this pull request Apr 18, 2025
Clean up printing code by switching to `llvm::interleaved` from llvm#135517.
kuhar added a commit to kuhar/llvm-project that referenced this pull request Apr 18, 2025
Clean up printing code by switching to `llvm::interleaved` from llvm#135517.
kuhar added a commit to kuhar/llvm-project that referenced this pull request Apr 18, 2025
Clean up printing code by switching to `llvm::interleaved` from llvm#135517.
Also make some minor readability & performance fixes.
kuhar added a commit that referenced this pull request Apr 18, 2025
Clean up printing code by switching to `llvm::interleaved` from
#135517.
kuhar added a commit that referenced this pull request Apr 18, 2025
Clean up printing code by switching to `llvm::interleaved` from
#135517. Also make some minor
readability & performance fixes.
kuhar added a commit that referenced this pull request Apr 18, 2025
…136248)

Clean up printing code by switching to `llvm::interleaved` from
#135517.
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Apr 18, 2025
Clean up printing code by switching to `llvm::interleaved` from
llvm/llvm-project#135517.
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Apr 18, 2025
Clean up printing code by switching to `llvm::interleaved` from
llvm/llvm-project#135517. Also make some minor
readability & performance fixes.
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Apr 18, 2025
…ts. NFC. (#136248)

Clean up printing code by switching to `llvm::interleaved` from
llvm/llvm-project#135517.
kuhar added a commit to kuhar/llvm-project that referenced this pull request Apr 18, 2025
* Use `llvm::interleaved` from llvm#135517 to simplify printing
* Avoid needless vector allocations
kuhar added a commit that referenced this pull request Apr 18, 2025
* Use `llvm::interleaved` from #135517 to simplify printing
* Avoid needless vector allocations
kuhar added a commit to kuhar/llvm-project that referenced this pull request Apr 19, 2025
Use `llvm::interleaved` from llvm#135517 to simplify printing.
kuhar added a commit that referenced this pull request Apr 19, 2025
Use `llvm::interleaved` from #135517 to simplify printing.
kuhar added a commit to kuhar/llvm-project that referenced this pull request Apr 19, 2025
Use `llvm::interleaved` from llvm#135517 to simplify printing.
kuhar added a commit to kuhar/llvm-project that referenced this pull request Apr 19, 2025
Use `llvm::interleaved` from llvm#135517 to simplify printing.
kuhar added a commit to kuhar/llvm-project that referenced this pull request Apr 19, 2025
Use `llvm::interleaved` from llvm#135517 to simplify printing.
kuhar added a commit that referenced this pull request Apr 20, 2025
Use `llvm::interleaved` from #135517 to simplify printing.
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