mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 10:42:39 +01:00
[Support] Add a basic C API for llvm::Error.
Summary: The C-API supports consuming errors, converting an error to a string error message, and querying an error's type. Other LLVM C APIs that wish to use llvm::Error can supply error-type-id checkers and custom error-to-structured-type converters for any custom errors they provide. Reviewers: bogner, zturner, labath, dblaikie Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D50716 llvm-svn: 339802
This commit is contained in:
parent
7557bac2f3
commit
3302570b39
65
include/llvm-c/Error.h
Normal file
65
include/llvm-c/Error.h
Normal file
@ -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
|
@ -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 @@ class LLVM_NODISCARD Error {
|
||||
// error.
|
||||
template <typename T> 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 @@ private:
|
||||
std::function<int(const Error &)> GetExitCode;
|
||||
};
|
||||
|
||||
/// Conversion from Error to LLVMErrorRef for C error bindings.
|
||||
inline LLVMErrorRef wrap(Error Err) {
|
||||
return reinterpret_cast<LLVMErrorRef>(Err.takePayload().release());
|
||||
}
|
||||
|
||||
/// Conversion from LLVMErrorRef to Error for C error bindings.
|
||||
inline Error unwrap(LLVMErrorRef ErrRef) {
|
||||
return Error(std::unique_ptr<ErrorInfoBase>(
|
||||
reinterpret_cast<ErrorInfoBase *>(ErrRef)));
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_SUPPORT_ERROR_H
|
||||
|
@ -126,6 +126,26 @@ void report_fatal_error(Error Err, bool GenCrashDiag) {
|
||||
report_fatal_error(ErrMsg);
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
LLVMErrorTypeId LLVMGetErrorTypeId(LLVMErrorRef Err) {
|
||||
return reinterpret_cast<ErrorInfoBase *>(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<void *>(&StringError::ID);
|
||||
}
|
||||
|
||||
#ifndef _MSC_VER
|
||||
|
@ -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 @@ TEST(Error, ErrorMatchers) {
|
||||
" 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<CustomError>(0))),
|
||||
Failed<CustomError>())
|
||||
<< "Failed to round-trip Error failure value via C API";
|
||||
|
||||
auto Err =
|
||||
wrap(make_error<StringError>("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<CustomSubError>(42, 7),
|
||||
make_error<CustomError>(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
|
||||
|
Loading…
Reference in New Issue
Block a user