This is an automated email from the ASF dual-hosted git repository.
Seven-Streams 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 1a2e530f [FEAT][Rust] Let a static_init_block! end without Ok(())
(#883)
1a2e530f is described below
commit 1a2e530fa68f5a251e3dea8b24d2a7ba19614a14
Author: Linzhang Li <[email protected]>
AuthorDate: Tue Oct 27 20:33:20 2026 -0400
[FEAT][Rust] Let a static_init_block! end without Ok(()) (#883)
## Summary
The body of a `tvm_ffi::static_init_block!` (#882) was the body of a
closure that returns
`Result<()>`, so every block ended in an `Ok(())` that carried no
information:
```rust
tvm_ffi::static_init_block! {
Function::register_global_typed("my_ext.add_one", add_one, "Add one to
an integer.")?;
Ok(())
}
```
This PR lets a block end without it, as C++ `TVM_FFI_STATIC_INIT_BLOCK`
does:
```rust
tvm_ffi::static_init_block! {
Function::register_global_typed("my_ext.add_one", add_one, "Add one to
an integer.")?;
}
```
---
rust/tvm-ffi/examples/static_init.rs | 1 -
rust/tvm-ffi/src/static_init.rs | 61 +++++++++++++++++++++++++++++++---
rust/tvm-ffi/tests/test_static_init.rs | 31 +++++++++++++++--
3 files changed, 85 insertions(+), 8 deletions(-)
diff --git a/rust/tvm-ffi/examples/static_init.rs
b/rust/tvm-ffi/examples/static_init.rs
index eb49faba..fbc46fbf 100644
--- a/rust/tvm-ffi/examples/static_init.rs
+++ b/rust/tvm-ffi/examples/static_init.rs
@@ -29,7 +29,6 @@ fn add_one(x: i64) -> Result<i64> {
tvm_ffi::static_init_block! {
Function::register_global_typed("static_init_example.add_one", add_one,
"Add one to an integer.")?;
- Ok(())
}
// The errors of the blocks that failed when the library loaded, which Python
raises as
diff --git a/rust/tvm-ffi/src/static_init.rs b/rust/tvm-ffi/src/static_init.rs
index 323fad21..6b5a631a 100644
--- a/rust/tvm-ffi/src/static_init.rs
+++ b/rust/tvm-ffi/src/static_init.rs
@@ -36,8 +36,10 @@ use crate::{Any, Error, Function, Result, INTERNAL_ERROR};
pub use linkme;
/// Run code when the program or library that holds it loads, as a C++
-/// `TVM_FFI_STATIC_INIT_BLOCK` does. The body is a block that returns
[`Result<()>`](crate::Result):
-/// it registers what the library defines, such as global functions, and stops
at its first error.
+/// `TVM_FFI_STATIC_INIT_BLOCK` does. The body is the body of a function that
returns
+/// [`Result<()>`](crate::Result): it registers what the library defines, such
as global functions,
+/// and stops at its first error, which `?` returns. A body whose statements
all end in `;` returns
+/// `Ok(())`; one that ends in an expression returns it, a `Result<()>`.
///
/// ```
/// use tvm_ffi::{Function, Result};
@@ -48,7 +50,6 @@ pub use linkme;
///
/// tvm_ffi::static_init_block! {
/// Function::register_global_typed("my_ext.add_one", add_one, "Add one to
an integer.")?;
-/// Ok(())
/// }
///
/// // Registered when the program loaded.
@@ -88,8 +89,14 @@ macro_rules! static_init_block {
None => "",
},
stringify!($($body)*),
- || -> $crate::Result<()> { $($body)* },
+ __tvm_ffi_static_init_block_body,
);
+ // A function item rather than a closure, to carry the attribute:
a body that diverges,
+ // such as one that panics, makes the conversion of its value
unreachable.
+ #[allow(unreachable_code)]
+ fn __tvm_ffi_static_init_block_body() -> $crate::Result<()> {
+
$crate::static_init::IntoStaticInitResult::into_static_init_result({ $($body)*
})
+ }
#[used]
#[cfg_attr(target_os = "linux", link_section = ".init_array")]
#[cfg_attr(target_os = "macos", link_section =
"__DATA,__mod_init_func")]
@@ -99,6 +106,52 @@ macro_rules! static_init_block {
};
}
+/// The value of the body of a
[`static_init_block!`](crate::static_init_block), converted to the
+/// outcome of the block: `()`, of a body whose statements all end in `;`, is
`Ok(())`, a
+/// [`Result<()>`](crate::Result) is itself, and a body that diverges, as one
that panics or ends
+/// in `return`, has no value to convert.
+#[doc(hidden)]
+#[diagnostic::on_unimplemented(
+ message = "a static init block returns `Result<()>`, not `{Self}`",
+ label = "the value of the block",
+ note = "end the last statement of the block with `;`, or return a
`Result<()>`"
+)]
+pub trait IntoStaticInitResult {
+ fn into_static_init_result(self) -> Result<()>;
+}
+
+impl IntoStaticInitResult for () {
+ fn into_static_init_result(self) -> Result<()> {
+ Ok(())
+ }
+}
+
+impl IntoStaticInitResult for Result<()> {
+ fn into_static_init_result(self) -> Result<()> {
+ self
+ }
+}
+
+/// The never type `!`, which stable Rust names only as the return type of a
function pointer.
+/// The value of a body that diverges is `!`, or `()` where an edition before
2024 falls back to it.
+#[doc(hidden)]
+pub trait FnOutput {
+ type Output;
+}
+
+impl<T> FnOutput for fn() -> T {
+ type Output = T;
+}
+
+#[doc(hidden)]
+pub type Never = <fn() -> ! as FnOutput>::Output;
+
+impl IntoStaticInitResult for Never {
+ fn into_static_init_result(self) -> Result<()> {
+ self
+ }
+}
+
/// A [`static_init_block!`](crate::static_init_block), gathered at link time.
#[doc(hidden)]
pub struct StaticInitBlock {
diff --git a/rust/tvm-ffi/tests/test_static_init.rs
b/rust/tvm-ffi/tests/test_static_init.rs
index ec0122e8..f1e4d460 100644
--- a/rust/tvm-ffi/tests/test_static_init.rs
+++ b/rust/tvm-ffi/tests/test_static_init.rs
@@ -31,9 +31,9 @@ fn add_one(x: i64) -> Result<i64> {
tvm_ffi::static_init_block! {
Function::register_global_typed("test_static_init.add_one", add_one, "Add
one.")?;
- Ok(())
}
+// A block may also end in the `Result<()>` it returns.
mod elsewhere {
use super::*;
@@ -43,6 +43,28 @@ mod elsewhere {
}
}
+// A block that returns early, and one that ends in `return`, which `!` types.
+mod returning {
+ use super::*;
+
+ fn body() -> Result<i64> {
+ Ok(8)
+ }
+
+ tvm_ffi::static_init_block! {
+ Function::register_global_typed("test_static_init.returning", body,
"")?;
+ if Function::get_global("test_static_init.returning").is_ok() {
+ return Ok(());
+ }
+ Function::register_global_typed("test_static_init.not_reached", body,
"")?;
+ }
+
+ tvm_ffi::static_init_block! {
+ Function::register_global_typed("test_static_init.returned", body,
"")?;
+ return Ok(())
+ }
+}
+
// Blocks that fail, which `run_static_init_blocks` reports together while it
runs the others: a
// block stops at its first error, and a panic is an error.
mod failing {
@@ -52,7 +74,6 @@ mod failing {
Function::register_global_typed("test_static_init.twice", add_one,
"")?;
Function::register_global_typed("test_static_init.twice", add_one,
"")?;
Function::register_global_typed("test_static_init.after_broken",
add_one, "")?;
- Ok(())
}
tvm_ffi::static_init_block! {
@@ -76,6 +97,10 @@ fn blocks_run_when_the_program_loads() {
2
);
assert_eq!(call_i64("test_static_init.elsewhere").unwrap(), 7);
+ // A block's own items are in scope, not shadowed by those of the macro.
+ assert_eq!(call_i64("test_static_init.returning").unwrap(), 8);
+ assert_eq!(call_i64("test_static_init.returned").unwrap(), 8);
+ assert!(Function::get_global("test_static_init.not_reached").is_err());
// The block that failed registered what came before its error, and
stopped there.
assert!(Function::get_global("test_static_init.twice").is_ok());
@@ -86,7 +111,7 @@ fn blocks_run_when_the_program_loads() {
.iter()
.filter(|block| block.identity().starts_with("test_static_init"))
.count();
- assert_eq!(blocks, 5);
+ assert_eq!(blocks, 7);
}
#[test]