Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove Parsing of C++ Exception String #10637

Closed
wants to merge 15 commits into from
64 changes: 46 additions & 18 deletions cpp/include/cudf/utilities/error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,37 +99,65 @@ struct fatal_cuda_error : public cuda_error {
* @brief Macro for checking (pre-)conditions that throws an exception when
* a condition is violated.
*
* Defaults to throwing `cudf::logic_error`, but a custom exception may also be
* specified.
*
* Example usage:
*
* @code
* CUDF_EXPECTS(lhs->dtype == rhs->dtype, "Column type mismatch");
* @endcode
* // throws cudf::logic_error
* CUDF_EXPECTS(lhs.type() != rhs.type(), "Column type mismatch");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

== ? (or else this is expecting lhs and rhs to having mismatching types so the error string is backwards?)

*
* @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::invalid_argument
* CUDF_EXPECTS(not cudf::is_nested(child_col.type()), std::invalid_argument,
* "Nested types are not supported.");
* @endcode
*/
#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 Doxygen_Suppress
#define GET_CUDF_EXPECTS_MACRO(_1, _2, _3, NAME, ...) NAME

/** @param[in] _condition Expression that evaluates to true or false
* @param[in] _expection_type The exception type to throw; must inherit
* `std::exception`. If not specified (i.e. if only two macro
Comment on lines +124 to +125
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a static_assert for this while we're at it.

* arguments are provided), defaults to `cudf::logic_error`
* @param[in] _what String literal description of why the exception was
* thrown, i.e. why `_condition` was expected to be true.
* @throw `_exception_type` if the condition evaluates to 0 (false).
*/
#define CUDF_EXPECTS_3(_condition, _exception_type, _reason) \
(!!(_condition)) ? static_cast<void>(0) : throw _exception_type \
{ \
"cuDF failure at: " __FILE__ ":" CUDF_STRINGIFY(__LINE__) ": " _reason \
}
#define CUDF_EXPECTS_2(_condition, _reason) CUDF_EXPECTS_3(_condition, cudf::logic_error, _reason)
//! @endcond

/**
* @brief Indicates that an erroneous code path has been taken.
*
* In host code, throws a `cudf::logic_error`.
*
*
* Example usage:
* ```
* ```c++
* // Throws `cudf::logic_error`
* CUDF_FAIL("Non-arithmetic operation is not supported");
* ```
*
* @param[in] reason String literal description of the reason
* // Throws `std::invalid_argument`
* CUDF_FAIL("Unsupported type for operation", std::invalid_argument);
* ```
*/
#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 Doxygen_Suppress
#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};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe for DRY this should just call CUDF_EXPECTS(false, _exception_type, _what)?

#define CUDF_FAIL_1(_what) CUDF_FAIL_2(_what, cudf::logic_error)
//! @endcond

namespace cudf {
namespace detail {
Expand Down
10 changes: 8 additions & 2 deletions cpp/include/cudf_test/cudf_gtest.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,14 @@ struct TypeList<Types<TYPES...>> {
* @param x The statement to be tested
* @param msg The message associated with the exception
*/
#define CUDF_EXPECT_THROW_MESSAGE(x, msg) \
EXPECT_THROW_MESSAGE(x, cudf::logic_error, "cuDF failure at:", msg)
#define CUDF_EXPECT_THROW_MESSAGE(...) \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know when these test macros snuck in, but I recall a long time ago advocating strongly against them. I think it's fragile and unimportant for us to be testing for the exact contents of an exceptions error message.

Don't block this PR on removing these, but file it away in your memory banks for future work.

GET_CUDF_EXPECT_THROW_MESSAGE_MACRO( \
__VA_ARGS__, CUDF_EXPECT_THROW_MESSAGE_3, CUDF_EXPECT_THROW_MESSAGE_2) \
(__VA_ARGS__)
#define GET_CUDF_EXPECT_THROW_MESSAGE_MACRO(_1, _2, _3, NAME, ...) NAME
#define CUDF_EXPECT_THROW_MESSAGE_3(x, exception, msg) \
EXPECT_THROW_MESSAGE(x, exception, "cuDF failure at:", msg)
#define CUDF_EXPECT_THROW_MESSAGE_2(x, msg) CUDF_EXPECT_THROW_MESSAGE_3(x, cudf::logic_error, msg)

/**
* @brief test macro to be expected to throw cudf::cuda_error with a message
Expand Down
2 changes: 1 addition & 1 deletion cpp/src/binaryop/binaryop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ std::unique_ptr<column> binary_operation(LhsType const& lhs,
return cudf::binops::compiled::string_null_min_max(lhs, rhs, op, output_type, stream, mr);

if (not cudf::binops::compiled::is_supported_operation(output_type, lhs.type(), rhs.type(), op))
CUDF_FAIL("Unsupported operator for these types");
CUDF_FAIL("Unsupported operator for these types", std::invalid_argument);

if (cudf::is_fixed_point(lhs.type()) or cudf::is_fixed_point(rhs.type())) {
cudf::binops::compiled::fixed_point_binary_operation_validation(
Expand Down
1 change: 1 addition & 0 deletions cpp/src/copying/scatter.cu
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,7 @@ std::unique_ptr<table> scatter(std::vector<std::reference_wrapper<const scalar>>
[n_rows] __device__(size_type index) {
return ((index >= -n_rows) && (index < n_rows));
}),
std::out_of_range,
"Scatter map index out of bounds");
}

Expand Down
3 changes: 2 additions & 1 deletion cpp/src/groupby/sort/scan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include <rmm/cuda_stream_view.hpp>

#include <memory>
#include <stdexcept>

namespace cudf {
namespace groupby {
Expand All @@ -55,7 +56,7 @@ struct scan_result_functor final : store_result_functor {
template <aggregation::Kind k>
void operator()(aggregation const& agg)
{
CUDF_FAIL("Unsupported groupby scan aggregation");
CUDF_FAIL("Unsupported groupby scan aggregation", std::invalid_argument);
}

private:
Expand Down
9 changes: 5 additions & 4 deletions cpp/src/unary/cast_ops.cu
Original file line number Diff line number Diff line change
Expand Up @@ -363,14 +363,15 @@ struct dispatch_unary_cast_to {
rmm::mr::device_memory_resource*)

{
if (!cudf::is_fixed_width<TargetT>())
if (!cudf::is_fixed_width<TargetT>()) {
CUDF_FAIL("Column type must be numeric or chrono or decimal32/64/128");
else if (cudf::is_fixed_point<SourceT>())
} else if (cudf::is_fixed_point<SourceT>()) {
CUDF_FAIL("Currently only decimal32/64/128 to floating point/integral is supported");
else if (cudf::is_timestamp<SourceT>() && is_numeric<TargetT>())
} else if (cudf::is_timestamp<SourceT>() && is_numeric<TargetT>()) {
CUDF_FAIL("Timestamps can be created only from duration");
else
} else {
CUDF_FAIL("Timestamps cannot be converted to numeric without converting it to a duration");
}
}
};

Expand Down
2 changes: 1 addition & 1 deletion cpp/tests/binaryop/binop-compiled-fixed_point-test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -683,7 +683,7 @@ TYPED_TEST(FixedPointCompiledTest, FixedPointBinaryOpThrows)
auto const col = fp_wrapper<RepType>{{100, 300, 500, 700}, scale_type{-2}};
auto const non_bool_type = data_type{type_to_id<decimalXX>(), -2};
EXPECT_THROW(cudf::binary_operation(col, col, cudf::binary_operator::LESS, non_bool_type),
cudf::logic_error);
std::invalid_argument);
}

TYPED_TEST(FixedPointCompiledTest, FixedPointBinaryOpModSimple)
Expand Down
5 changes: 3 additions & 2 deletions cpp/tests/copying/scatter_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <cudf_test/column_wrapper.hpp>
#include <cudf_test/table_utilities.hpp>
#include <cudf_test/type_lists.hpp>
#include <stdexcept>

class ScatterUntypedTests : public cudf::test::BaseFixture {
};
Expand Down Expand Up @@ -181,8 +182,8 @@ TYPED_TEST(ScatterIndexTypeTests, ScatterScalarOutOfBounds)

auto const target_table = cudf::table_view({target});

EXPECT_THROW(cudf::scatter(source_vector, upper_bound, target_table, true), cudf::logic_error);
EXPECT_THROW(cudf::scatter(source_vector, lower_bound, target_table, true), cudf::logic_error);
EXPECT_THROW(cudf::scatter(source_vector, upper_bound, target_table, true), std::out_of_range);
EXPECT_THROW(cudf::scatter(source_vector, lower_bound, target_table, true), std::out_of_range);
}

// Validate that each of the index types work
Expand Down
12 changes: 7 additions & 5 deletions cpp/tests/groupby/count_scan_tests.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, NVIDIA CORPORATION.
* Copyright (c) 2021-2022, NVIDIA CORPORATION.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -14,6 +14,7 @@
* limitations under the License.
*/

#include <stdexcept>
#include <tests/groupby/groupby_test_util.hpp>

#include <cudf_test/base_fixture.hpp>
Expand Down Expand Up @@ -55,6 +56,7 @@ TYPED_TEST(groupby_count_scan_test, basic)

auto agg1 = cudf::make_count_aggregation<groupby_scan_aggregation>();
CUDF_EXPECT_THROW_MESSAGE(test_single_scan(keys, vals, expect_keys, expect_vals, std::move(agg1)),
std::invalid_argument,
"Unsupported groupby scan aggregation");

auto agg2 = cudf::make_count_aggregation<groupby_scan_aggregation>(null_policy::INCLUDE);
Expand Down Expand Up @@ -173,20 +175,19 @@ TYPED_TEST(FixedPointTestAllReps, GroupByCountScan)
using result_wrapper = fixed_width_column_wrapper<R, int32_t>;

auto const scale = scale_type{-1};
// clang-format off
auto const keys = key_wrapper{1, 2, 3, 1, 2, 2, 1, 3, 3, 2};
auto const vals = fp_wrapper{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, scale};
auto const keys = key_wrapper{1, 2, 3, 1, 2, 2, 1, 3, 3, 2};
auto const vals = fp_wrapper{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, scale};

auto const expect_keys = key_wrapper{1, 1, 1, 2, 2, 2, 2, 3, 3, 3};
auto const expect_vals = result_wrapper{0, 1, 2, 0, 1, 2, 3, 0, 1, 2};
// clang-format on

CUDF_EXPECT_THROW_MESSAGE(
test_single_scan(keys,
vals,
expect_keys,
expect_vals,
cudf::make_count_aggregation<groupby_scan_aggregation>()),
std::invalid_argument,
"Unsupported groupby scan aggregation");

auto agg2 = cudf::make_count_aggregation<groupby_scan_aggregation>(null_policy::INCLUDE);
Expand All @@ -211,6 +212,7 @@ TEST_F(groupby_dictionary_count_scan_test, basic)

auto agg1 = cudf::make_count_aggregation<groupby_scan_aggregation>();
CUDF_EXPECT_THROW_MESSAGE(test_single_scan(keys, vals, expect_keys, expect_vals, std::move(agg1)),
std::invalid_argument,
"Unsupported groupby scan aggregation");
test_single_scan(keys,
vals,
Expand Down