[llvm] [Support] Add WrappedError class (PR #191706)

via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 16 06:59:01 PDT 2026


https://github.com/aokblast updated https://github.com/llvm/llvm-project/pull/191706

>From 8a9d0f98a88e398947a6181f93a3017256d10999 Mon Sep 17 00:00:00 2001
From: ShengYi Hung <aokblast at FreeBSD.org>
Date: Sun, 12 Apr 2026 20:13:20 +0800
Subject: [PATCH] [Support] Add WrappedError class

The error consumer filters duplicate errors based on a portion of the
error message. Introduce a new Error kind that carries a prefix string
to support this use case.
---
 llvm/include/llvm/Support/Error.h    | 47 ++++++++++++++++++++++++++++
 llvm/lib/Support/Error.cpp           |  6 ++++
 llvm/unittests/Support/ErrorTest.cpp | 29 +++++++++++++++++
 3 files changed, 82 insertions(+)

diff --git a/llvm/include/llvm/Support/Error.h b/llvm/include/llvm/Support/Error.h
index c9fd16fdb7c2b..8e414428c8286 100644
--- a/llvm/include/llvm/Support/Error.h
+++ b/llvm/include/llvm/Support/Error.h
@@ -1497,6 +1497,53 @@ inline Error unwrap(LLVMErrorRef ErrRef) {
       reinterpret_cast<ErrorInfoBase *>(ErrRef)));
 }
 
+class LLVM_ABI ContextualizedError : public ErrorInfo<ContextualizedError> {
+public:
+  ContextualizedError(std::unique_ptr<ErrorInfoBase> E,
+                      const Twine &Prefix = "")
+      : Err(std::move(E)), Context(Prefix.str()) {}
+
+  void log(raw_ostream &OS) const override {
+    assert(Err && "Trying to log after takeError().");
+    if (Context.size())
+      OS << Context << ": ";
+    Err->log(OS);
+  }
+
+  Error takeError() { return Error(std::move(Err)); }
+
+  const std::string &getContext() const { return Context; }
+
+  std::string getMessageWithoutContext() const {
+    std::string Msg;
+    raw_string_ostream OS(Msg);
+    Err->log(OS);
+    return Msg;
+  }
+
+  std::error_code convertToErrorCode() const override;
+
+  static Error build(Error E, const Twine &Prefix) {
+    std::unique_ptr<ErrorInfoBase> Payload;
+    handleAllErrors(std::move(E),
+                    [&](std::unique_ptr<ErrorInfoBase> EIB) -> Error {
+                      Payload = std::move(EIB);
+                      return Error::success();
+                    });
+    return Error(std::unique_ptr<ContextualizedError>(
+        new ContextualizedError(std::move(Payload), Prefix)));
+  }
+
+  static char ID;
+
+private:
+  std::unique_ptr<ErrorInfoBase> Err;
+  std::string Context;
+};
+
+inline Error createContextualizedError(Error E, const Twine &Prefix = "") {
+  return ContextualizedError::build(std::move(E), Prefix);
+}
 } // end namespace llvm
 
 #endif // LLVM_SUPPORT_ERROR_H
diff --git a/llvm/lib/Support/Error.cpp b/llvm/lib/Support/Error.cpp
index c6743155ced85..aabb701b9b999 100644
--- a/llvm/lib/Support/Error.cpp
+++ b/llvm/lib/Support/Error.cpp
@@ -205,3 +205,9 @@ LLVMErrorTypeId LLVMGetStringErrorTypeId() {
 LLVMErrorRef LLVMCreateStringError(const char *ErrMsg) {
   return wrap(make_error<StringError>(ErrMsg, inconvertibleErrorCode()));
 }
+
+char ContextualizedError::ID = 0;
+
+std::error_code ContextualizedError::convertToErrorCode() const {
+  return Err->convertToErrorCode();
+}
diff --git a/llvm/unittests/Support/ErrorTest.cpp b/llvm/unittests/Support/ErrorTest.cpp
index 45c0a4f450b51..4ce269d6b71b0 100644
--- a/llvm/unittests/Support/ErrorTest.cpp
+++ b/llvm/unittests/Support/ErrorTest.cpp
@@ -18,6 +18,8 @@
 #include "gtest/gtest-spi.h"
 #include "gtest/gtest.h"
 #include <memory>
+#include <string>
+#include <unordered_set>
 
 using namespace llvm;
 
@@ -1219,4 +1221,31 @@ TEST(Error, ForwardToExpected) {
   EXPECT_THAT_ERROR(ExpectedReturningFct(false).moveInto(MaybeV), Succeeded());
   EXPECT_EQ(*MaybeV, 42);
 }
+
+TEST(Error, DeduplicateByContextualized) {
+  std::unordered_set<std::string> Visit;
+
+  auto InsertError = [&](Error E) {
+    std::string InnerErrorStr;
+    EXPECT_THAT_ERROR(handleErrors(std::move(E),
+                                   [&](const ContextualizedError &E) {
+                                     InnerErrorStr =
+                                         E.getMessageWithoutContext();
+                                   }),
+                      Succeeded());
+    return Visit.insert(InnerErrorStr).second;
+  };
+  EXPECT_EQ(
+      InsertError(createContextualizedError(
+          createStringError("failed to execute operation A"), "Context A")),
+      true);
+  EXPECT_EQ(
+      InsertError(createContextualizedError(
+          createStringError("failed to execute operation B"), "Context A")),
+      true);
+  EXPECT_EQ(
+      InsertError(createContextualizedError(
+          createStringError("failed to execute operation A"), "Context B")),
+      false);
+}
 } // namespace



More information about the llvm-commits mailing list