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>();

Reply via email to