Skip to content

Commit

Permalink
Enable specifying exceptions in error macros (#12078)
Browse files Browse the repository at this point in the history
This change enables libcudf APIs throwing exceptions other than `cudf::logic_error`. This code was adapted from rmm. This contributes to #10200.

Authors:
  - Vyas Ramasubramani (https://github.com/vyasr)

Approvers:
  - Yunsong Wang (https://github.com/PointKernel)
  - Lawrence Mitchell (https://github.com/wence-)

URL: #12078
  • Loading branch information
vyasr authored Dec 2, 2022
1 parent 2bba970 commit 7026638
Showing 1 changed file with 64 additions and 20 deletions.
84 changes: 64 additions & 20 deletions cpp/include/cudf/utilities/error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <cuda_runtime_api.h>
#include <stdexcept>
#include <string>
#include <type_traits>

namespace cudf {
/**
Expand Down Expand Up @@ -99,37 +100,80 @@ struct fatal_cuda_error : public cuda_error {
* @brief Macro for checking (pre-)conditions that throws an exception when
* a condition is violated.
*
* Example usage:
* Defaults to throwing `cudf::logic_error`, but a custom exception may also be
* specified.
*
* @code
* CUDF_EXPECTS(lhs->dtype == rhs->dtype, "Column type mismatch");
* @endcode
* Example usage:
* ```
* // throws cudf::logic_error
* CUDF_EXPECTS(p != nullptr, "Unexpected null pointer");
*
* @param[in] cond Expression that evaluates to true or false
* @param[in] reason String literal description of the reason that cond is
* expected to be true
* @throw cudf::logic_error if the condition evaluates to false.
* // throws std::runtime_error
* CUDF_EXPECTS(p != nullptr, "Unexpected nullptr", std::runtime_error);
* ```
* @param ... This macro accepts either two or three arguments:
* - The first argument must be an expression that evaluates to true or
* false, and is the condition being checked.
* - The second argument is a string literal used to construct the `what` of
* the exception.
* - When given, the third argument is the exception to be thrown. When not
* specified, defaults to `cudf::logic_error`.
* @throw `_exception_type` if the condition evaluates to 0 (false).
*/
#define CUDF_EXPECTS(cond, reason) \
(!!(cond)) ? static_cast<void>(0) \
: throw cudf::logic_error("cuDF failure at: " __FILE__ \
":" CUDF_STRINGIFY(__LINE__) ": " reason)
#define CUDF_EXPECTS(...) \
GET_CUDF_EXPECTS_MACRO(__VA_ARGS__, CUDF_EXPECTS_3, CUDF_EXPECTS_2) \
(__VA_ARGS__)

/// @cond

#define GET_CUDF_EXPECTS_MACRO(_1, _2, _3, NAME, ...) NAME

#define CUDF_EXPECTS_3(_condition, _reason, _exception_type) \
do { \
static_assert(std::is_base_of_v<std::exception, _exception_type>); \
(_condition) ? static_cast<void>(0) \
: throw _exception_type /*NOLINT(bugprone-macro-parentheses)*/ \
{"CUDF failure at: " __FILE__ ":" CUDF_STRINGIFY(__LINE__) ": " _reason}; \
} while (0)

#define CUDF_EXPECTS_2(_condition, _reason) CUDF_EXPECTS_3(_condition, _reason, cudf::logic_error)

/// @endcond

/**
* @brief Indicates that an erroneous code path has been taken.
*
* In host code, throws a `cudf::logic_error`.
*
*
* Example usage:
* ```
* CUDF_FAIL("Non-arithmetic operation is not supported");
* ```c++
* // Throws `cudf::logic_error`
* CUDF_FAIL("Unsupported code path");
*
* // Throws `std::runtime_error`
* CUDF_FAIL("Unsupported code path", std::runtime_error);
* ```
*
* @param[in] reason String literal description of the reason
* @param ... This macro accepts either one or two arguments:
* - The first argument is a string literal used to construct the `what` of
* the exception.
* - When given, the second argument is the exception to be thrown. When not
* specified, defaults to `cudf::logic_error`.
* @throw `_exception_type` if the condition evaluates to 0 (false).
*/
#define CUDF_FAIL(reason) \
throw cudf::logic_error("cuDF failure at: " __FILE__ ":" CUDF_STRINGIFY(__LINE__) ": " reason)
#define CUDF_FAIL(...) \
GET_CUDF_FAIL_MACRO(__VA_ARGS__, CUDF_FAIL_2, CUDF_FAIL_1) \
(__VA_ARGS__)

/// @cond

#define GET_CUDF_FAIL_MACRO(_1, _2, NAME, ...) NAME

#define CUDF_FAIL_2(_what, _exception_type) \
/*NOLINTNEXTLINE(bugprone-macro-parentheses)*/ \
throw _exception_type { "CUDF failure at:" __FILE__ ":" CUDF_STRINGIFY(__LINE__) ": " _what }

#define CUDF_FAIL_1(_what) CUDF_FAIL_2(_what, cudf::logic_error)

/// @endcond

namespace cudf {
namespace detail {
Expand Down

0 comments on commit 7026638

Please sign in to comment.