[llvm] r270948 - [Support] Add a StringError convenience class to Error.h

Lang Hames via llvm-commits llvm-commits at lists.llvm.org
Thu May 26 18:37:34 PDT 2016


Author: lhames
Date: Thu May 26 20:37:32 2016
New Revision: 270948

URL: http://llvm.org/viewvc/llvm-project?rev=270948&view=rev
Log:
[Support] Add a StringError convenience class to Error.h

StringError can be used to represent Errors that aren't recoverable based on
the error type, but that have a useful error message that can be reported to
the user or logged.


Modified:
    llvm/trunk/include/llvm/Support/Error.h
    llvm/trunk/lib/Support/Error.cpp
    llvm/trunk/unittests/Support/ErrorTest.cpp

Modified: llvm/trunk/include/llvm/Support/Error.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/Error.h?rev=270948&r1=270947&r2=270948&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/Error.h (original)
+++ llvm/trunk/include/llvm/Support/Error.h Thu May 26 20:37:32 2016
@@ -26,6 +26,7 @@ namespace llvm {
 
 class Error;
 class ErrorList;
+class Twine;
 
 /// Base class for error info classes. Do not extend this directly: Extend
 /// the ErrorInfo template subclass instead.
@@ -850,24 +851,22 @@ protected:
   std::error_code EC;
 };
 
+/// The value returned by this function can be returned from convertToErrorCode
+/// for Error values where no sensible translation to std::error_code exists.
+/// It should only be used in this situation, and should never be used where a
+/// sensible conversion to std::error_code is available, as attempts to convert
+/// to/from this error will result in a fatal error. (i.e. it is a programmatic
+///error to try to convert such a value).
+std::error_code unconvertibleErrorCode();
+
 /// Helper for converting an std::error_code to a Error.
-inline Error errorCodeToError(std::error_code EC) {
-  if (!EC)
-    return Error::success();
-  return Error(llvm::make_unique<ECError>(ECError(EC)));
-}
+Error errorCodeToError(std::error_code EC);
 
 /// Helper for converting an ECError to a std::error_code.
 ///
 /// This method requires that Err be Error() or an ECError, otherwise it
 /// will trigger a call to abort().
-inline std::error_code errorToErrorCode(Error Err) {
-  std::error_code EC;
-  handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) {
-    EC = EI.convertToErrorCode();
-  });
-  return EC;
-}
+std::error_code errorToErrorCode(Error Err);
 
 /// Convert an ErrorOr<T> to an Expected<T>.
 template <typename T> Expected<T> errorOrToExpected(ErrorOr<T> &&EO) {
@@ -883,6 +882,23 @@ template <typename T> ErrorOr<T> expecte
   return std::move(*E);
 }
 
+/// This class wraps a string in an Error.
+///
+/// StringError is useful in cases where the client is not expected to be able
+/// to consume the specific error message programmatically (for example, if the
+/// error message is to be presented to the user). It cannot be converted to a
+/// std::error_code.
+class StringError : public ErrorInfo<StringError> {
+public:
+  static char ID;
+  StringError(const Twine &S, std::error_code EC);
+  void log(raw_ostream &OS) const override;
+  std::error_code convertToErrorCode() const override;
+private:
+  std::string Msg;
+  std::error_code EC;
+};
+
 /// Helper for check-and-exit error handling.
 ///
 /// For tool use only. NOT FOR USE IN LIBRARY CODE.

Modified: llvm/trunk/lib/Support/Error.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Error.cpp?rev=270948&r1=270947&r2=270948&view=diff
==============================================================================
--- llvm/trunk/lib/Support/Error.cpp (original)
+++ llvm/trunk/lib/Support/Error.cpp Thu May 26 20:37:32 2016
@@ -8,15 +8,19 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/Support/Error.h"
+
+#include "llvm/ADT/Twine.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/ManagedStatic.h"
 
+
 using namespace llvm;
 
 namespace {
 
-  enum class ErrorErrorCode {
-    MultipleErrors
+  enum class ErrorErrorCode : int {
+    MultipleErrors = 1,
+    UnconvertibleError
   };
 
   // FIXME: This class is only here to support the transition to llvm::Error. It
@@ -30,21 +34,61 @@ namespace {
       switch (static_cast<ErrorErrorCode>(condition)) {
       case ErrorErrorCode::MultipleErrors:
         return "Multiple errors";
-      };
+      case ErrorErrorCode::UnconvertibleError:
+        return "Unconvertible error value. An error has occurred that could "
+               "not be converted to a known std::error_code. Please file a "
+               "bug.";
+      }
       llvm_unreachable("Unhandled error code");
     }
   };
 
 }
 
+static ManagedStatic<ErrorErrorCategory> ErrorErrorCat;
+
+namespace llvm {
+
 void ErrorInfoBase::anchor() {}
 char ErrorInfoBase::ID = 0;
 char ErrorList::ID = 0;
 char ECError::ID = 0;
+char StringError::ID = 0;
 
-static ManagedStatic<ErrorErrorCategory> ErrorErrorCat;
 
 std::error_code ErrorList::convertToErrorCode() const {
   return std::error_code(static_cast<int>(ErrorErrorCode::MultipleErrors),
                          *ErrorErrorCat);
 }
+
+std::error_code unconvertibleErrorCode() {
+  return std::error_code(static_cast<int>(ErrorErrorCode::UnconvertibleError),
+                         *ErrorErrorCat);
+}
+
+Error errorCodeToError(std::error_code EC) {
+  if (!EC)
+    return Error::success();
+  return Error(llvm::make_unique<ECError>(ECError(EC)));
+}
+
+std::error_code errorToErrorCode(Error Err) {
+  std::error_code EC;
+  handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) {
+    EC = EI.convertToErrorCode();
+  });
+  if (EC == unconvertibleErrorCode())
+    report_fatal_error(EC.message());
+  return EC;
+}
+
+StringError::StringError(const Twine &S, std::error_code EC)
+    : Msg(S.str()), EC(EC) {}
+
+void StringError::log(raw_ostream &OS) const { OS << Msg; }
+
+std::error_code StringError::convertToErrorCode() const {
+  return EC;
+}
+
+}

Modified: llvm/trunk/unittests/Support/ErrorTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/ErrorTest.cpp?rev=270948&r1=270947&r2=270948&view=diff
==============================================================================
--- llvm/trunk/unittests/Support/ErrorTest.cpp (original)
+++ llvm/trunk/unittests/Support/ErrorTest.cpp Thu May 26 20:37:32 2016
@@ -8,6 +8,8 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/Support/Error.h"
+
+#include "llvm/ADT/Twine.h"
 #include "llvm/Support/Errc.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "gtest/gtest.h"
@@ -376,6 +378,20 @@ TEST(Error, CatchErrorFromHandler) {
       << "Failed to handle Error returned from handleErrors.";
 }
 
+TEST(Error, StringError) {
+  std::string Msg;
+  raw_string_ostream S(Msg);
+  logAllUnhandledErrors(make_error<StringError>("foo" + Twine(42),
+                                                unconvertibleErrorCode()),
+                        S, "");
+  EXPECT_EQ(S.str(), "foo42\n") << "Unexpected StringError log result";
+
+  auto EC =
+    errorToErrorCode(make_error<StringError>("", errc::invalid_argument));
+  EXPECT_EQ(EC, errc::invalid_argument)
+    << "Failed to convert StringError to error_code.";
+}
+
 // Test that the ExitOnError utility works as expected.
 TEST(Error, ExitOnError) {
   ExitOnError ExitOnErr;




More information about the llvm-commits mailing list