forked from KhronosGroup/SYCL-CTS
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsycl_exceptions.h
183 lines (154 loc) · 5.17 KB
/
sycl_exceptions.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/*******************************************************************************
//
// SYCL 2020 Conformance Test Suite
//
// Provides stringification and matchers for SYCL exceptions
//
*******************************************************************************/
#ifndef __SYCLCTS_UTIL_SYCL_EXCEPTIONS_H
#define __SYCLCTS_UTIL_SYCL_EXCEPTIONS_H
#include <catch2/catch_tostring.hpp>
#include <catch2/matchers/catch_matchers_templated.hpp>
#include <sycl/sycl.hpp>
#include "../tests/common/macros.h" // To ensure FAIL macro replaced properly
#include "conversion.h"
#include "logger.h"
#include "sycl_enums.h"
#include <sstream>
#include <string>
#include <system_error>
#include <utility>
// TODO: Remove when all implementations support the sycl::exception API
// entirely
#if SYCL_CTS_COMPILING_WITH_ADAPTIVECPP
#define SYCL_CTS_SUPPORT_HAS_EXCEPTION_CODE 1
#define SYCL_CTS_SUPPORT_HAS_EXCEPTION_CATEGORY 0
#define SYCL_CTS_SUPPORT_HAS_MAKE_ERROR_CODE 0
#elif SYCL_CTS_COMPILING_WITH_DPCPP
// Feature flags for DPC++
#define SYCL_CTS_SUPPORT_HAS_EXCEPTION_CODE 1
#define SYCL_CTS_SUPPORT_HAS_EXCEPTION_CATEGORY 1
#define SYCL_CTS_SUPPORT_HAS_MAKE_ERROR_CODE 0
#else
#define SYCL_CTS_SUPPORT_HAS_EXCEPTION_CODE 1
#define SYCL_CTS_SUPPORT_HAS_EXCEPTION_CATEGORY 1
#define SYCL_CTS_SUPPORT_HAS_MAKE_ERROR_CODE 1
#endif
namespace sycl_cts::util {
/**
* Helper function to get details for SYCL exception
* Can be used, for example, for INFO(... << stringify_sycl_exception(ex))
* expressions
*/
std::string stringify_sycl_exception(const sycl::exception& e);
/**
* Matchers' implementation details
*/
namespace detail {
/**
* Matcher for std::error_category value, with no error code comparison
*/
class matcher_exception_category : public Catch::Matchers::MatcherGenericBase {
public:
matcher_exception_category(const std::error_category& category)
: m_category(category) {}
bool match([[maybe_unused]] const sycl::exception& other) const {
#if SYCL_CTS_SUPPORT_HAS_EXCEPTION_CATEGORY == 0
// There should be no compilation failures, but every CHECK_THROWS_MATCHES
// should fail with this matcher
return false;
#else
return other.category() == m_category;
#endif
}
std::string describe() const override {
return std::string("has category: '") + m_category.name() + "'";
}
private:
const std::error_category& m_category;
};
#if SYCL_CTS_SUPPORT_HAS_ERRC_ENUM == 1
/**
* Matcher for sycl::errc error codes
* C++ provides semantic match for std::error_code by operator==, still SYCL
* doesn't support std::error_condition, so we have a strict equality check
* here
*/
struct matcher_equals_exception
: public Catch::Matchers::MatcherGenericBase {
matcher_equals_exception(const sycl::errc& code_value)
: m_code_value(code_value) {}
bool match(const sycl::exception& other) const {
#if SYCL_CTS_SUPPORT_HAS_EXCEPTION_CODE == 0
// There should be no compilation failures, but every CHECK_THROWS_MATCHES
// should fail with this matcher
return false;
#else
// Compare two std::error_code instances
return std::is_error_code_enum_v<sycl::errc> &&
(other.code() == m_code_value);
#endif // SYCL_CTS_SUPPORT_HAS_EXCEPTION_CODE
}
std::string describe() const override {
using CodeStringMakerT = Catch::StringMaker<sycl::errc>;
std::ostringstream result;
result << "has code value ";
result << to_integral(m_code_value);
result << " (" << CodeStringMakerT::convert(m_code_value) << ")";
result << " for sycl_category";
return result.str();
}
private:
const sycl::errc& m_code_value;
};
#endif // SYCL_CTS_SUPPORT_HAS_ERRC_ENUM
} // namespace detail
/**
* Provides matcher for std::error_category value, with no error code
* comparison
*
* Usage example:
* CHECK_THROWS_MATCHES(action, sycl::exception,
* has_exception_category(sycl::sycl_category()));
*/
inline auto has_exception_category(const std::error_category& category) {
return detail::matcher_exception_category(category);
}
#if SYCL_CTS_SUPPORT_HAS_ERRC_ENUM == 1
/**
* Provides matcher for sycl::errc error codes with sycl_category check
*
* Usage example:
* CHECK_THROWS_MATCHES(action, sycl::exception,
* equals_exception(sycl::errc::feature_not_supported) ||
* equals_exception(sycl::errc::invalid));
*/
inline auto equals_exception(const sycl::errc& code) {
return detail::matcher_equals_exception(code);
}
#endif // SYCL_CTS_SUPPORT_HAS_ERRC_ENUM == 1
} // namespace sycl_cts::util
/**
* Stringification of SYCL exceptions for Catch2 tests
* Required for custom matchers output
*/
namespace Catch {
template <>
struct StringMaker<sycl::exception> {
static std::string convert(const sycl::exception& e) {
return ::sycl_cts::util::stringify_sycl_exception(e);
}
};
} // namespace Catch
/**
* Helper function to log details for SYCL exception for legacy tests
*
* Deprecated, use Catch2 macroses for new tests instead
*/
namespace {
inline void log_exception(sycl_cts::util::logger&, const sycl::exception& e) {
// Print multi-line message in a single Catch2 warning
WARN(sycl_cts::util::stringify_sycl_exception(e));
}
} // anonymous namespace
#endif // __SYCLCTS_UTIL_SYCL_EXCEPTIONS_H