Index: llvm/trunk/include/llvm-c/Error.h =================================================================== --- llvm/trunk/include/llvm-c/Error.h +++ llvm/trunk/include/llvm-c/Error.h @@ -0,0 +1,65 @@ +/*===------- llvm-c/Error.h - llvm::Error class C Interface -------*- C -*-===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This file defines the C interface to LLVM's Error class. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_ERROR_H +#define LLVM_C_ERROR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Opaque reference to an error instance. Null serves as the 'success' value. + */ +typedef struct LLVMOpaqueError *LLVMErrorRef; + +/** + * Error type identifier. + */ +typedef const void *LLVMErrorTypeId; + +/** + * Returns the type id for the given error instance, which must be a failure + * value (i.e. non-null). + */ +LLVMErrorTypeId LLVMGetErrorTypeId(LLVMErrorRef Err); + +/** + * Dispose of the given error without handling it. This operation consumes the + * error, and the given LLVMErrorRef value is not usable once this call returns. + * Note: This method *only* needs to be called if the error is not being passed + * to some other consuming operation, e.g. LLVMGetErrorMessage. + */ +void LLVMConsumeError(LLVMErrorRef Err); + +/** + * Returns the given string's error message. This operation consumes the error, + * and the given LLVMErrorRef value is not usable once this call returns. + */ +char *LLVMGetErrorMessage(LLVMErrorRef Err); + +/** + * Dispose of the given error message. + */ +void LLVMDisposeErrorMessage(char *ErrMsg); + +/** + * Returns the type id for llvm StringError. + */ +LLVMErrorTypeId LLVMGetStringErrorTypeId(); + +#ifdef __cplusplus +} +#endif + +#endif Index: llvm/trunk/include/llvm/Support/Error.h =================================================================== --- llvm/trunk/include/llvm/Support/Error.h +++ llvm/trunk/include/llvm/Support/Error.h @@ -14,8 +14,9 @@ #ifndef LLVM_SUPPORT_ERROR_H #define LLVM_SUPPORT_ERROR_H -#include "llvm/ADT/SmallVector.h" +#include "llvm-c/Error.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Twine.h" #include "llvm/Config/abi-breaking.h" @@ -167,6 +168,9 @@ // error. template friend class Expected; + // wrap needs to be able to steal the payload. + friend LLVMErrorRef wrap(Error); + protected: /// Create a success value. Prefer using 'Error::success()' for readability Error() { @@ -1183,6 +1187,17 @@ std::function GetExitCode; }; +/// Conversion from Error to LLVMErrorRef for C error bindings. +inline LLVMErrorRef wrap(Error Err) { + return reinterpret_cast(Err.takePayload().release()); +} + +/// Conversion from LLVMErrorRef to Error for C error bindings. +inline Error unwrap(LLVMErrorRef ErrRef) { + return Error(std::unique_ptr( + reinterpret_cast(ErrRef))); +} + } // end namespace llvm #endif // LLVM_SUPPORT_ERROR_H Index: llvm/trunk/lib/Support/Error.cpp =================================================================== --- llvm/trunk/lib/Support/Error.cpp +++ llvm/trunk/lib/Support/Error.cpp @@ -126,6 +126,26 @@ report_fatal_error(ErrMsg); } +} // end namespace llvm + +LLVMErrorTypeId LLVMGetErrorTypeId(LLVMErrorRef Err) { + return reinterpret_cast(Err)->dynamicClassID(); +} + +void LLVMConsumeError(LLVMErrorRef Err) { consumeError(unwrap(Err)); } + +char *LLVMGetErrorMessage(LLVMErrorRef Err) { + std::string Tmp = toString(unwrap(Err)); + char *ErrMsg = new char[Tmp.size() + 1]; + memcpy(ErrMsg, Tmp.data(), Tmp.size()); + ErrMsg[Tmp.size()] = '\0'; + return ErrMsg; +} + +void LLVMDisposeErrorMessage(char *ErrMsg) { delete[] ErrMsg; } + +LLVMErrorTypeId LLVMGetStringErrorTypeId() { + return reinterpret_cast(&StringError::ID); } #ifndef _MSC_VER Index: llvm/trunk/unittests/Support/ErrorTest.cpp =================================================================== --- llvm/trunk/unittests/Support/ErrorTest.cpp +++ llvm/trunk/unittests/Support/ErrorTest.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Error.h" +#include "llvm-c/Error.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Errc.h" @@ -832,4 +833,35 @@ " Actual: failed (CustomError {0})"); } +TEST(Error, C_API) { + EXPECT_THAT_ERROR(unwrap(wrap(Error::success())), Succeeded()) + << "Failed to round-trip Error success value via C API"; + EXPECT_THAT_ERROR(unwrap(wrap(make_error(0))), + Failed()) + << "Failed to round-trip Error failure value via C API"; + + auto Err = + wrap(make_error("test message", inconvertibleErrorCode())); + EXPECT_EQ(LLVMGetErrorTypeId(Err), LLVMGetStringErrorTypeId()) + << "Failed to match error type ids via C API"; + char *ErrMsg = LLVMGetErrorMessage(Err); + EXPECT_STREQ(ErrMsg, "test message") + << "Failed to roundtrip StringError error message via C API"; + LLVMDisposeErrorMessage(ErrMsg); + + bool GotCSE = false; + bool GotCE = false; + handleAllErrors( + unwrap(wrap(joinErrors(make_error(42, 7), + make_error(42)))), + [&](CustomSubError &CSE) { + GotCSE = true; + }, + [&](CustomError &CE) { + GotCE = true; + }); + EXPECT_TRUE(GotCSE) << "Failed to round-trip ErrorList via C API"; + EXPECT_TRUE(GotCE) << "Failed to round-trip ErrorList via C API"; +} + } // end anon namespace