summaryrefslogtreecommitdiff
path: root/include/llvm/Support/Error.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/llvm/Support/Error.h')
-rw-r--r--include/llvm/Support/Error.h102
1 files changed, 96 insertions, 6 deletions
diff --git a/include/llvm/Support/Error.h b/include/llvm/Support/Error.h
index f13c9484b5fd5..a3482f5a58b53 100644
--- a/include/llvm/Support/Error.h
+++ b/include/llvm/Support/Error.h
@@ -64,6 +64,12 @@ public:
/// using std::error_code. It will be removed in the future.
virtual std::error_code convertToErrorCode() const = 0;
+ // Returns the class ID for this type.
+ static const void *classID() { return &ID; }
+
+ // Returns the class ID for the dynamic type of this ErrorInfoBase instance.
+ virtual const void *dynamicClassID() const = 0;
+
// Check whether this instance is a subclass of the class identified by
// ClassID.
virtual bool isA(const void *const ClassID) const {
@@ -75,9 +81,6 @@ public:
return isA(ErrorInfoT::classID());
}
- // Returns the class ID for this type.
- static const void *classID() { return &ID; }
-
private:
virtual void anchor();
@@ -233,6 +236,14 @@ public:
return getPtr() && getPtr()->isA(ErrT::classID());
}
+ /// Returns the dynamic class id of this error, or null if this is a success
+ /// value.
+ const void* dynamicClassID() const {
+ if (!getPtr())
+ return nullptr;
+ return getPtr()->dynamicClassID();
+ }
+
private:
void assertIsChecked() {
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
@@ -316,11 +327,14 @@ template <typename ErrT, typename... ArgTs> Error make_error(ArgTs &&... Args) {
template <typename ThisErrT, typename ParentErrT = ErrorInfoBase>
class ErrorInfo : public ParentErrT {
public:
+
+ static const void *classID() { return &ThisErrT::ID; }
+
+ const void *dynamicClassID() const override { return &ThisErrT::ID; }
+
bool isA(const void *const ClassID) const override {
return ClassID == classID() || ParentErrT::isA(ClassID);
}
-
- static const void *classID() { return &ThisErrT::ID; }
};
/// Special ErrorInfo subclass representing a list of ErrorInfos.
@@ -629,6 +643,7 @@ private:
/// takeError(). It also adds an bool errorIsA<ErrT>() method for testing the
/// error class type.
template <class T> class LLVM_NODISCARD Expected {
+ template <class T1> friend class ExpectedAsOutParameter;
template <class OtherT> friend class Expected;
static const bool isRef = std::is_reference<T>::value;
typedef ReferenceStorage<typename std::remove_reference<T>::type> wrap;
@@ -737,7 +752,7 @@ public:
/// \brief Check that this Expected<T> is an error of type ErrT.
template <typename ErrT> bool errorIsA() const {
- return HasError && getErrorStorage()->template isA<ErrT>();
+ return HasError && (*getErrorStorage())->template isA<ErrT>();
}
/// \brief Take ownership of the stored error.
@@ -832,6 +847,18 @@ private:
return reinterpret_cast<error_type *>(ErrorStorage.buffer);
}
+ const error_type *getErrorStorage() const {
+ assert(HasError && "Cannot get error when a value exists!");
+ return reinterpret_cast<const error_type *>(ErrorStorage.buffer);
+ }
+
+ // Used by ExpectedAsOutParameter to reset the checked flag.
+ void setUnchecked() {
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+ Unchecked = true;
+#endif
+ }
+
void assertIsChecked() {
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
if (Unchecked) {
@@ -858,6 +885,28 @@ private:
#endif
};
+/// Helper for Expected<T>s used as out-parameters.
+///
+/// See ErrorAsOutParameter.
+template <typename T>
+class ExpectedAsOutParameter {
+public:
+
+ ExpectedAsOutParameter(Expected<T> *ValOrErr)
+ : ValOrErr(ValOrErr) {
+ if (ValOrErr)
+ (void)!!*ValOrErr;
+ }
+
+ ~ExpectedAsOutParameter() {
+ if (ValOrErr)
+ ValOrErr->setUnchecked();
+ }
+
+private:
+ Expected<T> *ValOrErr;
+};
+
/// This class wraps a std::error_code in a Error.
///
/// This is useful if you're writing an interface that returns a Error
@@ -926,6 +975,8 @@ public:
void log(raw_ostream &OS) const override;
std::error_code convertToErrorCode() const override;
+ const std::string &getMessage() const { return Msg; }
+
private:
std::string Msg;
std::error_code EC;
@@ -985,6 +1036,45 @@ private:
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err,
bool gen_crash_diag = true);
+/// Report a fatal error if Err is a failure value.
+///
+/// This function can be used to wrap calls to fallible functions ONLY when it
+/// is known that the Error will always be a success value. E.g.
+///
+/// @code{.cpp}
+/// // foo only attempts the fallible operation if DoFallibleOperation is
+/// // true. If DoFallibleOperation is false then foo always returns
+/// // Error::success().
+/// Error foo(bool DoFallibleOperation);
+///
+/// cantFail(foo(false));
+/// @endcode
+inline void cantFail(Error Err) {
+ if (Err)
+ llvm_unreachable("Failure value returned from cantFail wrapped call");
+}
+
+/// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and
+/// returns the contained value.
+///
+/// This function can be used to wrap calls to fallible functions ONLY when it
+/// is known that the Error will always be a success value. E.g.
+///
+/// @code{.cpp}
+/// // foo only attempts the fallible operation if DoFallibleOperation is
+/// // true. If DoFallibleOperation is false then foo always returns an int.
+/// Expected<int> foo(bool DoFallibleOperation);
+///
+/// int X = cantFail(foo(false));
+/// @endcode
+template <typename T>
+T cantFail(Expected<T> ValOrErr) {
+ if (ValOrErr)
+ return std::move(*ValOrErr);
+ else
+ llvm_unreachable("Failure value returned from cantFail wrapped call");
+}
+
} // end namespace llvm
#endif // LLVM_SUPPORT_ERROR_H