This is an automated email from the ASF dual-hosted git repository.
tqchen pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm-ffi.git
The following commit(s) were added to refs/heads/main by this push:
new 35cbc327 [ERROR] Complete support of CHECK macros (#465)
35cbc327 is described below
commit 35cbc3274cf4b02d8d2e34d2510be5b34d0046ea
Author: Tianqi Chen <[email protected]>
AuthorDate: Thu Feb 19 18:10:22 2026 -0500
[ERROR] Complete support of CHECK macros (#465)
This PR completes the support of CHECK macros
for DCHECK and CHECK_EQ with error types.
---
include/tvm/ffi/error.h | 65 +++++++++++++++++++++++++++++----------
tests/cpp/test_error.cc | 81 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 130 insertions(+), 16 deletions(-)
diff --git a/include/tvm/ffi/error.h b/include/tvm/ffi/error.h
index 3ecfbb72..1b6cb47a 100644
--- a/include/tvm/ffi/error.h
+++ b/include/tvm/ffi/error.h
@@ -450,27 +450,60 @@ TVM_FFI_CHECK_FUNC(_NE, !=)
#endif
} // namespace details
-#define TVM_FFI_ICHECK_BINARY_OP(name, op, x, y)
\
- if (auto __tvm_ffi_log_err = /* NOLINT(bugprone-reserved-identifier) */
\
- ::tvm::ffi::details::LogCheck##name(x, y))
\
- TVM_FFI_THROW(InternalError) << "Check failed: " << #x " " #op " " #y <<
*__tvm_ffi_log_err \
- << ": "
-
-#define TVM_FFI_ICHECK(x) \
- if (!(x)) TVM_FFI_THROW(InternalError) << "Check failed: (" #x << ") is
false: "
+#define TVM_FFI_CHECK_BINARY_OP(name, op, x, y, ErrorKind) \
+ if (auto __tvm_ffi_log_err = /* NOLINT(bugprone-reserved-identifier) */ \
+ ::tvm::ffi::details::LogCheck##name(x, y)) \
+ TVM_FFI_THROW(ErrorKind) << "Check failed: " << #x " " #op " " #y <<
*__tvm_ffi_log_err << ": "
#define TVM_FFI_CHECK(cond, ErrorKind) \
if (!(cond)) TVM_FFI_THROW(ErrorKind) << "Check failed: (" #cond << ") is
false: "
-#define TVM_FFI_ICHECK_LT(x, y) TVM_FFI_ICHECK_BINARY_OP(_LT, <, x, y)
-#define TVM_FFI_ICHECK_GT(x, y) TVM_FFI_ICHECK_BINARY_OP(_GT, >, x, y)
-#define TVM_FFI_ICHECK_LE(x, y) TVM_FFI_ICHECK_BINARY_OP(_LE, <=, x, y)
-#define TVM_FFI_ICHECK_GE(x, y) TVM_FFI_ICHECK_BINARY_OP(_GE, >=, x, y)
-#define TVM_FFI_ICHECK_EQ(x, y) TVM_FFI_ICHECK_BINARY_OP(_EQ, ==, x, y)
-#define TVM_FFI_ICHECK_NE(x, y) TVM_FFI_ICHECK_BINARY_OP(_NE, !=, x, y)
-#define TVM_FFI_ICHECK_NOTNULL(x)
\
- ((x) == nullptr ? TVM_FFI_THROW(InternalError) << "Check not null: " #x << '
', \
+#define TVM_FFI_CHECK_LT(x, y, ErrorKind) TVM_FFI_CHECK_BINARY_OP(_LT, <, x,
y, ErrorKind)
+#define TVM_FFI_CHECK_GT(x, y, ErrorKind) TVM_FFI_CHECK_BINARY_OP(_GT, >, x,
y, ErrorKind)
+#define TVM_FFI_CHECK_LE(x, y, ErrorKind) TVM_FFI_CHECK_BINARY_OP(_LE, <=, x,
y, ErrorKind)
+#define TVM_FFI_CHECK_GE(x, y, ErrorKind) TVM_FFI_CHECK_BINARY_OP(_GE, >=, x,
y, ErrorKind)
+#define TVM_FFI_CHECK_EQ(x, y, ErrorKind) TVM_FFI_CHECK_BINARY_OP(_EQ, ==, x,
y, ErrorKind)
+#define TVM_FFI_CHECK_NE(x, y, ErrorKind) TVM_FFI_CHECK_BINARY_OP(_NE, !=, x,
y, ErrorKind)
+#define TVM_FFI_CHECK_NOTNULL(x, ErrorKind) \
+ ((x) == nullptr ? TVM_FFI_THROW(ErrorKind) << "Check not null: " #x << ' ', \
(x) : (x)) // NOLINT(*)
+
+#define TVM_FFI_ICHECK(x) TVM_FFI_CHECK(x, InternalError)
+#define TVM_FFI_ICHECK_LT(x, y) TVM_FFI_CHECK_LT(x, y, InternalError)
+#define TVM_FFI_ICHECK_GT(x, y) TVM_FFI_CHECK_GT(x, y, InternalError)
+#define TVM_FFI_ICHECK_LE(x, y) TVM_FFI_CHECK_LE(x, y, InternalError)
+#define TVM_FFI_ICHECK_GE(x, y) TVM_FFI_CHECK_GE(x, y, InternalError)
+#define TVM_FFI_ICHECK_EQ(x, y) TVM_FFI_CHECK_EQ(x, y, InternalError)
+#define TVM_FFI_ICHECK_NE(x, y) TVM_FFI_CHECK_NE(x, y, InternalError)
+#define TVM_FFI_ICHECK_NOTNULL(x) TVM_FFI_CHECK_NOTNULL(x, InternalError)
+
+// Debug checks: same as ICHECK but stripped when NDEBUG is defined (release
builds).
+#ifndef NDEBUG
+#define TVM_FFI_DCHECK(x) TVM_FFI_ICHECK(x)
+#define TVM_FFI_DCHECK_LT(x, y) TVM_FFI_ICHECK_LT(x, y)
+#define TVM_FFI_DCHECK_GT(x, y) TVM_FFI_ICHECK_GT(x, y)
+#define TVM_FFI_DCHECK_LE(x, y) TVM_FFI_ICHECK_LE(x, y)
+#define TVM_FFI_DCHECK_GE(x, y) TVM_FFI_ICHECK_GE(x, y)
+#define TVM_FFI_DCHECK_EQ(x, y) TVM_FFI_ICHECK_EQ(x, y)
+#define TVM_FFI_DCHECK_NE(x, y) TVM_FFI_ICHECK_NE(x, y)
+#define TVM_FFI_DCHECK_NOTNULL(x) TVM_FFI_ICHECK_NOTNULL(x)
+#else
+#define TVM_FFI_DCHECK(x) \
+ while (false) TVM_FFI_ICHECK(x)
+#define TVM_FFI_DCHECK_LT(x, y) \
+ while (false) TVM_FFI_ICHECK_LT(x, y)
+#define TVM_FFI_DCHECK_GT(x, y) \
+ while (false) TVM_FFI_ICHECK_GT(x, y)
+#define TVM_FFI_DCHECK_LE(x, y) \
+ while (false) TVM_FFI_ICHECK_LE(x, y)
+#define TVM_FFI_DCHECK_GE(x, y) \
+ while (false) TVM_FFI_ICHECK_GE(x, y)
+#define TVM_FFI_DCHECK_EQ(x, y) \
+ while (false) TVM_FFI_ICHECK_EQ(x, y)
+#define TVM_FFI_DCHECK_NE(x, y) \
+ while (false) TVM_FFI_ICHECK_NE(x, y)
+#define TVM_FFI_DCHECK_NOTNULL(x) (x)
+#endif // NDEBUG
} // namespace ffi
} // namespace tvm
#endif // TVM_FFI_ERROR_H_
diff --git a/tests/cpp/test_error.cc b/tests/cpp/test_error.cc
index 6a520ee8..7a16a000 100644
--- a/tests/cpp/test_error.cc
+++ b/tests/cpp/test_error.cc
@@ -107,6 +107,87 @@ TEST(CheckError, PassingCondition) {
EXPECT_NO_THROW(TVM_FFI_CHECK(5 < 10, IndexError));
}
+// Helper: expect that a throwing statement throws Error with the given kind
and
+// a message containing the expected substring.
+#define EXPECT_CHECK_ERROR(stmt, expected_kind, expected_substr) \
+ { \
+ bool caught = false; \
+ try { \
+ stmt; \
+ } catch (const ::tvm::ffi::Error& e) { \
+ caught = true; \
+ EXPECT_EQ(e.kind(), expected_kind); \
+ EXPECT_NE(e.message().find(expected_substr), std::string::npos) \
+ << "message: " << e.message(); \
+ } \
+ EXPECT_TRUE(caught) << "Expected " #stmt " to throw"; \
+ }
+
+TEST(CheckError, CheckBinaryOps) {
+ // EQ: pass and fail
+ TVM_FFI_CHECK_EQ(3, 3, ValueError);
+ EXPECT_CHECK_ERROR(TVM_FFI_CHECK_EQ(3, 5, ValueError), "ValueError", "3 vs.
5");
+ // NE: pass and fail
+ TVM_FFI_CHECK_NE(3, 4, ValueError);
+ EXPECT_CHECK_ERROR(TVM_FFI_CHECK_NE(3, 3, ValueError), "ValueError", "3 vs.
3");
+ // LT: pass and fail
+ TVM_FFI_CHECK_LT(3, 4, IndexError);
+ EXPECT_CHECK_ERROR(TVM_FFI_CHECK_LT(5, 3, IndexError), "IndexError", "5 vs.
3");
+ // GT: pass and fail
+ TVM_FFI_CHECK_GT(4, 3, IndexError);
+ EXPECT_CHECK_ERROR(TVM_FFI_CHECK_GT(3, 5, IndexError), "IndexError", "3 vs.
5");
+ // LE: pass and fail
+ TVM_FFI_CHECK_LE(3, 3, TypeError);
+ TVM_FFI_CHECK_LE(2, 3, TypeError);
+ EXPECT_CHECK_ERROR(TVM_FFI_CHECK_LE(5, 3, TypeError), "TypeError", "5 vs.
3");
+ // GE: pass and fail
+ TVM_FFI_CHECK_GE(4, 3, TypeError);
+ TVM_FFI_CHECK_GE(3, 3, TypeError);
+ EXPECT_CHECK_ERROR(TVM_FFI_CHECK_GE(2, 5, TypeError), "TypeError", "2 vs.
5");
+ // NOTNULL: pass and fail
+ int x = 42;
+ int* p = &x;
+ EXPECT_EQ(TVM_FFI_CHECK_NOTNULL(p, ValueError), p);
+ int* q = nullptr;
+ EXPECT_CHECK_ERROR((void)TVM_FFI_CHECK_NOTNULL(q, ValueError), "ValueError",
"Check not null");
+}
+
+TEST(CheckError, DCheck) {
+#ifdef NDEBUG
+ // Release: failing conditions are no-ops.
+ TVM_FFI_DCHECK(false);
+ TVM_FFI_DCHECK_EQ(1, 2);
+ TVM_FFI_DCHECK_NE(1, 1);
+ TVM_FFI_DCHECK_LT(5, 3);
+ TVM_FFI_DCHECK_GT(3, 5);
+ TVM_FFI_DCHECK_LE(5, 3);
+ TVM_FFI_DCHECK_GE(3, 5);
+ int* q = nullptr;
+ int* r = TVM_FFI_DCHECK_NOTNULL(q);
+ EXPECT_EQ(r, nullptr);
+#else
+ // Debug: passing conditions succeed.
+ TVM_FFI_DCHECK(true);
+ TVM_FFI_DCHECK_EQ(3, 3);
+ TVM_FFI_DCHECK_NE(3, 4);
+ TVM_FFI_DCHECK_LT(3, 4);
+ TVM_FFI_DCHECK_GT(4, 3);
+ TVM_FFI_DCHECK_LE(3, 3);
+ TVM_FFI_DCHECK_GE(4, 3);
+ int x = 42;
+ int* p = &x;
+ EXPECT_EQ(TVM_FFI_DCHECK_NOTNULL(p), p);
+ // Debug: failing conditions throw InternalError.
+ EXPECT_CHECK_ERROR(TVM_FFI_DCHECK(false), "InternalError", "Check failed");
+ EXPECT_CHECK_ERROR(TVM_FFI_DCHECK_EQ(1, 2), "InternalError", "1 vs. 2");
+ EXPECT_CHECK_ERROR(TVM_FFI_DCHECK_NE(1, 1), "InternalError", "1 vs. 1");
+ EXPECT_CHECK_ERROR(TVM_FFI_DCHECK_LT(5, 3), "InternalError", "5 vs. 3");
+ EXPECT_CHECK_ERROR(TVM_FFI_DCHECK_GT(3, 5), "InternalError", "3 vs. 5");
+ EXPECT_CHECK_ERROR(TVM_FFI_DCHECK_LE(5, 3), "InternalError", "5 vs. 3");
+ EXPECT_CHECK_ERROR(TVM_FFI_DCHECK_GE(3, 5), "InternalError", "3 vs. 5");
+#endif
+}
+
TEST(Error, AnyConvert) {
Any any = Error("TypeError", "here", "test0");
Optional<Error> opt_err = any.as<Error>();