This is an automated email from the ASF dual-hosted git repository.
junrushao 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 4bccb3e [ERROR] Make Error conform more to std (#240)
4bccb3e is described below
commit 4bccb3eda0d543be67ec56204e045ca3e3b88641
Author: Tianqi Chen <[email protected]>
AuthorDate: Fri Nov 7 20:05:20 2025 -0500
[ERROR] Make Error conform more to std (#240)
This PR changes Error.what() to only return message. This helps to
conform to the standard that what should not throw. Added a
error.FullMessage() function to get the fullmessage with trace and kind.
This also helps us to remove TLS in the header side which can makes the
compiled c++ object more friendly wrt to LLVM JIT.
---
include/tvm/ffi/error.h | 20 ++++++++++++++------
tests/cpp/test_error.cc | 32 +++++++++++++++++---------------
2 files changed, 31 insertions(+), 21 deletions(-)
diff --git a/include/tvm/ffi/error.h b/include/tvm/ffi/error.h
index dd7b923..9560237 100644
--- a/include/tvm/ffi/error.h
+++ b/include/tvm/ffi/error.h
@@ -225,17 +225,25 @@ class Error : public ObjectRef, public std::exception {
obj->update_backtrace(obj, backtrace_str, update_mode);
}
+ /*!
+ * \brief Get the full message of the error, including kind, message and
traceback.
+ * \return The full message of the error object.
+ */
+ std::string FullMessage() const {
+ ErrorObj* obj = static_cast<ErrorObj*>(data_.get());
+ return (std::string("Traceback (most recent call last):\n") +
TracebackMostRecentCallLast() +
+ std::string(obj->kind.data, obj->kind.size) + std::string(": ") +
+ std::string(obj->message.data, obj->message.size) + '\n');
+ }
+
/*!
* \brief Get the error message
* \return The error message
+ * \note To get the full message including kind and traceback, use
FullMessage() instead.
*/
const char* what() const noexcept(true) override {
- thread_local std::string what_data;
ErrorObj* obj = static_cast<ErrorObj*>(data_.get());
- what_data = (std::string("Traceback (most recent call last):\n") +
- TracebackMostRecentCallLast() + std::string(obj->kind.data,
obj->kind.size) +
- std::string(": ") + std::string(obj->message.data,
obj->message.size) + '\n');
- return what_data.c_str();
+ return obj->message.data;
}
/// \cond Doxygen_Suppress
@@ -265,7 +273,7 @@ class ErrorBuilder {
[[noreturn]] ~ErrorBuilder() noexcept(false) {
::tvm::ffi::Error error(std::move(kind_), stream_.str(),
std::move(backtrace_));
if (log_before_throw_) {
- std::cerr << error.what();
+ std::cerr << error.FullMessage();
}
throw error;
}
diff --git a/tests/cpp/test_error.cc b/tests/cpp/test_error.cc
index 46ffe7c..283e4b9 100644
--- a/tests/cpp/test_error.cc
+++ b/tests/cpp/test_error.cc
@@ -35,10 +35,10 @@ TEST(Error, Backtrace) {
} catch (const Error& error) {
EXPECT_EQ(error.message(), "test0");
EXPECT_EQ(error.kind(), "RuntimeError");
- std::string what = error.what();
- EXPECT_NE(what.find("line"), std::string::npos);
- EXPECT_NE(what.find("ThrowRuntimeError"), std::string::npos);
- EXPECT_NE(what.find("RuntimeError: test0"), std::string::npos);
+ std::string full_message = error.FullMessage();
+ EXPECT_NE(full_message.find("line"), std::string::npos);
+ EXPECT_NE(full_message.find("ThrowRuntimeError"), std::string::npos);
+ EXPECT_NE(full_message.find("RuntimeError: test0"),
std::string::npos);
throw;
}
},
@@ -52,9 +52,9 @@ TEST(CheckError, Backtrace) {
TVM_FFI_ICHECK_GT(2, 3);
} catch (const Error& error) {
EXPECT_EQ(error.kind(), "InternalError");
- std::string what = error.what();
- EXPECT_NE(what.find("line"), std::string::npos);
- EXPECT_NE(what.find("2 > 3"), std::string::npos);
+ std::string full_message = error.FullMessage();
+ EXPECT_NE(full_message.find("line"), std::string::npos);
+ EXPECT_NE(full_message.find("2 > 3"), std::string::npos);
throw;
}
},
@@ -69,10 +69,10 @@ TEST(CheckError, ValueError) {
TVM_FFI_CHECK(value >= 0, ValueError) << "Value must be
non-negative, got " << value;
} catch (const Error& error) {
EXPECT_EQ(error.kind(), "ValueError");
- std::string what = error.what();
- EXPECT_NE(what.find("line"), std::string::npos);
- EXPECT_NE(what.find("Check failed: (value >= 0) is false"),
std::string::npos);
- EXPECT_NE(what.find("Value must be non-negative, got -5"),
std::string::npos);
+ std::string full_message = error.FullMessage();
+ EXPECT_NE(full_message.find("line"), std::string::npos);
+ EXPECT_NE(full_message.find("Check failed: (value >= 0) is false"),
std::string::npos);
+ EXPECT_NE(full_message.find("Value must be non-negative, got -5"),
std::string::npos);
throw;
}
},
@@ -89,10 +89,12 @@ TEST(CheckError, IndexError) {
<< "Index " << index << " out of bounds for array of size " <<
array_size;
} catch (const Error& error) {
EXPECT_EQ(error.kind(), "IndexError");
- std::string what = error.what();
- EXPECT_NE(what.find("line"), std::string::npos);
- EXPECT_NE(what.find("Check failed: (index < array_size) is false"),
std::string::npos);
- EXPECT_NE(what.find("Index 10 out of bounds for array of size 5"),
std::string::npos);
+ std::string full_message = error.FullMessage();
+ EXPECT_NE(full_message.find("line"), std::string::npos);
+ EXPECT_NE(full_message.find("Check failed: (index < array_size) is
false"),
+ std::string::npos);
+ EXPECT_NE(full_message.find("Index 10 out of bounds for array of
size 5"),
+ std::string::npos);
throw;
}
},