diff options
Diffstat (limited to 'parallel-libs/streamexecutor/include/streamexecutor/Error.h')
-rw-r--r-- | parallel-libs/streamexecutor/include/streamexecutor/Error.h | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/parallel-libs/streamexecutor/include/streamexecutor/Error.h b/parallel-libs/streamexecutor/include/streamexecutor/Error.h new file mode 100644 index 00000000000..b2d1ebb830d --- /dev/null +++ b/parallel-libs/streamexecutor/include/streamexecutor/Error.h @@ -0,0 +1,215 @@ +//===-- Error.h - Error handling --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Error types used in the public API and internally in StreamExecutor. +/// +/// StreamExecutor's error handling is based on the types streamexecutor::Error +/// and streamexecutor::Expected<T>. +/// +/// +/// \section error The Error Class +/// +/// The Error class either represents success or contains an error message +/// describing the cause of the error. Error instances are created by calling +/// Error::success for successes or make_error for errors. +/// +/// \code{.cpp} +/// Error achieveWorldPeace() { +/// if (WorldPeaceAlreadyAchieved) { +/// return Error::success(); +/// } else { +/// return make_error("Can't someone else do it?"); +/// } +/// } +/// \endcode +/// +/// Error instances are implicitly convertible to bool. Error values convert to +/// true and successes convert to false. Error instances must have their boolean +/// values checked or they must be moved before they go out of scope, otherwise +/// their destruction will cause the program to abort with a warning about an +/// unchecked Error. +/// +/// If the Error represents success, then checking the boolean value is all that +/// is required, but if the Error represents a real error, the Error value must +/// be consumed. The function consumeAndGetMessage is the way to extract the +/// error message from an Error and consume the Error at the same time, so +/// typical error handling will first check whether there was an error and then +/// extract the error message if so. Here is an example: +/// +/// \code{.cpp} +/// if (Error E = achieveWorldPeace()) { +/// printf("An error occurred: %s\n", consumeAndGetMessage(E).c_str()); +/// exit(EXIT_FAILURE): +/// } +/// \endcode +/// +/// It is also common to simply pass an error along up the call stack if it +/// cannot be handled in the current function. +/// +/// \code{.cpp} +/// Error doTask() { +/// if (Error E = achieveWorldPeace()) { +/// return E; +/// } +/// ... +/// } +/// \endcode +/// +/// There is also a function consumeError that consumes an error value without +/// fetching the error message. This is useful when we want to ignore an error. +/// +/// The dieIfError function is also provided for quick-and-dirty error handling. +/// +/// +/// \section expected The Expected Class +/// +/// The Expected<T> class either represents a value of type T or an Error. +/// Expected<T> has one constructor that takes a T value and another constructor +/// that takes an Error rvalue reference, so Expected instances can be +/// constructed either from values or from errors: +/// +/// \code{.cpp} +/// Expected<int> getMyFavoriteInt() { +/// int MyFavorite = 42; +/// if (IsThereAFavorite) { +/// return MyFavorite; +/// } else { +/// return make_error("I don't have a favorite"); +/// } +/// } +/// \endcode +/// +/// Expected<T> instances are implicitly convertible to bool and are true if +/// they contain a value and false if they contain an error. Note that this is +/// the opposite convention of the Error type conversion to bool, where true +/// meant error and false meant success. +/// +/// If the Expected<T> instance is not an error, the stored value can be +/// obtained by using operator*. If access to members of the value are desired +/// instead of the value itself, operator-> can be used as well. +/// +/// Expected<T> instances must have their boolean value checked or they must be +/// moved before they go out of scope, otherwise they will cause the program to +/// abort with a warning about an unchecked error. If the Expected<T> instance +/// contains a value, then checking the boolean value is all that is required, +/// but if it contains an Error object, that Error object must be handled by +/// calling Expected<T>::takeError() to get the underlying error. +/// +/// Here is an example of the use of an Expected<T> value returned from a +/// function: +/// +/// \code{.cpp} +/// Expected<int> ExpectedInt = getMyFavoriteInt(); +/// if (ExpectedInt) { +/// printf("My favorite integer is %d\n", *ExpectedInt); +/// } else { +/// printf("An error occurred: %s\n", +/// consumeAndGetMessage(ExpectedInt.takeError())); +/// exit(EXIT_FAILURE); +/// } +/// \endcode +/// +/// The following snippet shows some examples of how Errors and Expected values +/// can be passed up the stack if they should not be handled in the current +/// function. +/// +/// \code{.cpp} +/// Expected<double> doTask3() { +/// Error WorldPeaceError = achieveWorldPeace(); +/// if (!WorldPeaceError) { +/// return WorldPeaceError; +/// } +/// +/// Expected<martian> ExpectedMartian = getMyFavoriteMartian(); +/// if (!ExpectedMartian) { +/// // Must extract the error because martian cannot be converted to double. +/// return ExpectedMartian.takeError(): +/// } +/// +/// // It's fine to return Expected<int> for Expected<double> because int can +/// // be converted to double. +/// return getMyFavoriteInt(); +/// } +/// \endcode +/// +/// The getOrDie function is also available for quick-and-dirty error handling. +/// +/// +/// \section llvm Relation to llvm::Error and llvm::Expected +/// +/// The streamexecutor::Error and streamexecutor::Expected classes are actually +/// just their LLVM counterparts redeclared in the streamexectuor namespace, but +/// they should be treated as separate types, even so. +/// +/// StreamExecutor does not support any underlying llvm::ErrorInfo class except +/// the one it defines internally for itself, so a streamexecutor::Error can be +/// thought of as a restricted llvm::Error that is guaranteed to hold a specific +/// error type. +/// +/// Although code may compile if llvm functions used to handle these +/// StreamExecutor error types, it is likely that code will lead to runtime +/// errors, so it is strongly recommended that only the functions from the +/// streamexecutor namespace are used on these StreamExecutor error types. +/// +//===----------------------------------------------------------------------===// + +#ifndef STREAMEXECUTOR_ERROR_H +#define STREAMEXECUTOR_ERROR_H + +#include <cstdio> +#include <cstdlib> +#include <memory> +#include <string> + +#include "llvm/Support/Error.h" + +namespace streamexecutor { + +using llvm::consumeError; +using llvm::Error; +using llvm::Expected; +using llvm::Twine; + +/// Makes an Error object from an error message. +Error make_error(Twine Message); + +/// Consumes the input error and returns its error message. +/// +/// Assumes the input was created by the make_error function above. +std::string consumeAndGetMessage(Error &&E); + +/// Extracts the T value from an Expected<T> or prints an error message to +/// stderr and exits the program with code EXIT_FAILURE if the Expected<T> is an +/// error. +/// +/// This function and the dieIfError function are provided for applications that +/// are OK with aborting the program if an error occurs, and which don't have +/// any special error logging needs. Applications with different error handling +/// needs will likely want to declare their own functions with similar +/// signatures but which log error messages in a different way or attempt to +/// recover from errors instead of aborting the program. +template <typename T> T getOrDie(Expected<T> &&E) { + if (!E) { + std::fprintf(stderr, "Error extracting an expected value: %s.\n", + consumeAndGetMessage(E.takeError()).c_str()); + std::exit(EXIT_FAILURE); + } + return std::move(*E); +} + +/// Prints an error message to stderr and exits the program with code +/// EXIT_FAILURE if the input is an error. +/// +/// \sa getOrDie +void dieIfError(Error &&E); + +} // namespace streamexecutor + +#endif // STREAMEXECUTOR_ERROR_H |