Skip to content

Commit 00fb14d

Browse files
committedAug 15, 2018
[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
1 parent 5222cb6 commit 00fb14d

File tree

4 files changed

+133
-1
lines changed

4 files changed

+133
-1
lines changed
 

‎llvm/include/llvm-c/Error.h

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*===------- llvm-c/Error.h - llvm::Error class C Interface -------*- C -*-===*\
2+
|* *|
3+
|* The LLVM Compiler Infrastructure *|
4+
|* *|
5+
|* This file is distributed under the University of Illinois Open Source *|
6+
|* License. See LICENSE.TXT for details. *|
7+
|* *|
8+
|*===----------------------------------------------------------------------===*|
9+
|* *|
10+
|* This file defines the C interface to LLVM's Error class. *|
11+
|* *|
12+
\*===----------------------------------------------------------------------===*/
13+
14+
#ifndef LLVM_C_ERROR_H
15+
#define LLVM_C_ERROR_H
16+
17+
#ifdef __cplusplus
18+
extern "C" {
19+
#endif
20+
21+
/**
22+
* Opaque reference to an error instance. Null serves as the 'success' value.
23+
*/
24+
typedef struct LLVMOpaqueError *LLVMErrorRef;
25+
26+
/**
27+
* Error type identifier.
28+
*/
29+
typedef const void *LLVMErrorTypeId;
30+
31+
/**
32+
* Returns the type id for the given error instance, which must be a failure
33+
* value (i.e. non-null).
34+
*/
35+
LLVMErrorTypeId LLVMGetErrorTypeId(LLVMErrorRef Err);
36+
37+
/**
38+
* Dispose of the given error without handling it. This operation consumes the
39+
* error, and the given LLVMErrorRef value is not usable once this call returns.
40+
* Note: This method *only* needs to be called if the error is not being passed
41+
* to some other consuming operation, e.g. LLVMGetErrorMessage.
42+
*/
43+
void LLVMConsumeError(LLVMErrorRef Err);
44+
45+
/**
46+
* Returns the given string's error message. This operation consumes the error,
47+
* and the given LLVMErrorRef value is not usable once this call returns.
48+
*/
49+
char *LLVMGetErrorMessage(LLVMErrorRef Err);
50+
51+
/**
52+
* Dispose of the given error message.
53+
*/
54+
void LLVMDisposeErrorMessage(char *ErrMsg);
55+
56+
/**
57+
* Returns the type id for llvm StringError.
58+
*/
59+
LLVMErrorTypeId LLVMGetStringErrorTypeId();
60+
61+
#ifdef __cplusplus
62+
}
63+
#endif
64+
65+
#endif

‎llvm/include/llvm/Support/Error.h

+16-1
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@
1414
#ifndef LLVM_SUPPORT_ERROR_H
1515
#define LLVM_SUPPORT_ERROR_H
1616

17-
#include "llvm/ADT/SmallVector.h"
17+
#include "llvm-c/Error.h"
1818
#include "llvm/ADT/STLExtras.h"
19+
#include "llvm/ADT/SmallVector.h"
1920
#include "llvm/ADT/StringExtras.h"
2021
#include "llvm/ADT/Twine.h"
2122
#include "llvm/Config/abi-breaking.h"
@@ -167,6 +168,9 @@ class LLVM_NODISCARD Error {
167168
// error.
168169
template <typename T> friend class Expected;
169170

171+
// wrap needs to be able to steal the payload.
172+
friend LLVMErrorRef wrap(Error);
173+
170174
protected:
171175
/// Create a success value. Prefer using 'Error::success()' for readability
172176
Error() {
@@ -1183,6 +1187,17 @@ class ExitOnError {
11831187
std::function<int(const Error &)> GetExitCode;
11841188
};
11851189

1190+
/// Conversion from Error to LLVMErrorRef for C error bindings.
1191+
inline LLVMErrorRef wrap(Error Err) {
1192+
return reinterpret_cast<LLVMErrorRef>(Err.takePayload().release());
1193+
}
1194+
1195+
/// Conversion from LLVMErrorRef to Error for C error bindings.
1196+
inline Error unwrap(LLVMErrorRef ErrRef) {
1197+
return Error(std::unique_ptr<ErrorInfoBase>(
1198+
reinterpret_cast<ErrorInfoBase *>(ErrRef)));
1199+
}
1200+
11861201
} // end namespace llvm
11871202

11881203
#endif // LLVM_SUPPORT_ERROR_H

‎llvm/lib/Support/Error.cpp

+20
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,26 @@ void report_fatal_error(Error Err, bool GenCrashDiag) {
126126
report_fatal_error(ErrMsg);
127127
}
128128

129+
} // end namespace llvm
130+
131+
LLVMErrorTypeId LLVMGetErrorTypeId(LLVMErrorRef Err) {
132+
return reinterpret_cast<ErrorInfoBase *>(Err)->dynamicClassID();
133+
}
134+
135+
void LLVMConsumeError(LLVMErrorRef Err) { consumeError(unwrap(Err)); }
136+
137+
char *LLVMGetErrorMessage(LLVMErrorRef Err) {
138+
std::string Tmp = toString(unwrap(Err));
139+
char *ErrMsg = new char[Tmp.size() + 1];
140+
memcpy(ErrMsg, Tmp.data(), Tmp.size());
141+
ErrMsg[Tmp.size()] = '\0';
142+
return ErrMsg;
143+
}
144+
145+
void LLVMDisposeErrorMessage(char *ErrMsg) { delete[] ErrMsg; }
146+
147+
LLVMErrorTypeId LLVMGetStringErrorTypeId() {
148+
return reinterpret_cast<void *>(&StringError::ID);
129149
}
130150

131151
#ifndef _MSC_VER

‎llvm/unittests/Support/ErrorTest.cpp

+32
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
//===----------------------------------------------------------------------===//
99

1010
#include "llvm/Support/Error.h"
11+
#include "llvm-c/Error.h"
1112

1213
#include "llvm/ADT/Twine.h"
1314
#include "llvm/Support/Errc.h"
@@ -832,4 +833,35 @@ TEST(Error, ErrorMatchers) {
832833
" Actual: failed (CustomError {0})");
833834
}
834835

836+
TEST(Error, C_API) {
837+
EXPECT_THAT_ERROR(unwrap(wrap(Error::success())), Succeeded())
838+
<< "Failed to round-trip Error success value via C API";
839+
EXPECT_THAT_ERROR(unwrap(wrap(make_error<CustomError>(0))),
840+
Failed<CustomError>())
841+
<< "Failed to round-trip Error failure value via C API";
842+
843+
auto Err =
844+
wrap(make_error<StringError>("test message", inconvertibleErrorCode()));
845+
EXPECT_EQ(LLVMGetErrorTypeId(Err), LLVMGetStringErrorTypeId())
846+
<< "Failed to match error type ids via C API";
847+
char *ErrMsg = LLVMGetErrorMessage(Err);
848+
EXPECT_STREQ(ErrMsg, "test message")
849+
<< "Failed to roundtrip StringError error message via C API";
850+
LLVMDisposeErrorMessage(ErrMsg);
851+
852+
bool GotCSE = false;
853+
bool GotCE = false;
854+
handleAllErrors(
855+
unwrap(wrap(joinErrors(make_error<CustomSubError>(42, 7),
856+
make_error<CustomError>(42)))),
857+
[&](CustomSubError &CSE) {
858+
GotCSE = true;
859+
},
860+
[&](CustomError &CE) {
861+
GotCE = true;
862+
});
863+
EXPECT_TRUE(GotCSE) << "Failed to round-trip ErrorList via C API";
864+
EXPECT_TRUE(GotCE) << "Failed to round-trip ErrorList via C API";
865+
}
866+
835867
} // end anon namespace

0 commit comments

Comments
 (0)
Please sign in to comment.