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 583e4b7  [misc] support various arg types (#229)
583e4b7 is described below

commit 583e4b73c11aa3257e7be862834b98f33c39a6dd
Author: DarkSharpness <[email protected]>
AuthorDate: Mon Nov 10 07:03:44 2025 +0800

    [misc] support various arg types (#229)
    
    Related PR #228.
    
    We now support all kinds of argument type (T, const T, T&, const T&,
    T&&, const T&& have been tested) in C++ exported functions.
---
 include/tvm/ffi/function_details.h | 37 +++++++++++++++++++++++++++----------
 1 file changed, 27 insertions(+), 10 deletions(-)

diff --git a/include/tvm/ffi/function_details.h 
b/include/tvm/ffi/function_details.h
index e7db063..4cd67aa 100644
--- a/include/tvm/ffi/function_details.h
+++ b/include/tvm/ffi/function_details.h
@@ -53,11 +53,19 @@ struct Arg2Str {
   }
 };
 
+/// NOTE: We only support `T`, `const T`, `const T&` and `T&&` as argument 
types.
+template <typename T>
+static constexpr bool ArgTypeSupported =
+    (!std::is_reference_v<T>) ||
+    (std::is_const_v<std::remove_reference_t<T>> && 
std::is_lvalue_reference_v<T>) ||
+    (!std::is_const_v<std::remove_reference_t<T>> && 
std::is_rvalue_reference_v<T>);
+
 template <typename T>
 static constexpr bool ArgSupported =
-    (std::is_same_v<std::remove_const_t<std::remove_reference_t<T>>, Any> ||
-     std::is_same_v<std::remove_const_t<std::remove_reference_t<T>>, AnyView> 
||
-     TypeTraitsNoCR<T>::convert_enabled);
+    (ArgTypeSupported<T> &&
+     (std::is_same_v<std::remove_const_t<std::remove_reference_t<T>>, Any> ||
+      std::is_same_v<std::remove_const_t<std::remove_reference_t<T>>, AnyView> 
||
+      TypeTraitsNoCR<T>::convert_enabled));
 
 // NOTE: return type can only support non-reference managed returns
 template <typename T>
@@ -136,9 +144,19 @@ using FGetFuncSignature = std::string (*)();
 
 /*!
  * \brief Auxilary argument value with context for error reporting
+ * \tparam Type The expected type of the argument.
+ * \note We use a template class with non-template operator conversion
+ * instead of a non-template class with template operator conversion.
+ * This is because template operator conversion doesn't play well with
+ * classes with template constructors.
+ * In this case, it may lead to some unintended compiler errors.
+ * An example of class can be `std::optional<T>`.
  */
+template <typename Type>
 class ArgValueWithContext {
  public:
+  using TypeWithoutCR = std::remove_const_t<std::remove_reference_t<Type>>;
+
   /*!
    * \brief move constructor from another return value.
    * \param args The argument list
@@ -151,16 +169,13 @@ class ArgValueWithContext {
                                      const std::string* optional_name, 
FGetFuncSignature f_sig)
       : args_(args), arg_index_(arg_index), optional_name_(optional_name), 
f_sig_(f_sig) {}
 
-  template <typename Type>
-  TVM_FFI_INLINE operator Type() {  // NOLINT(google-explicit-constructor)
-    using TypeWithoutCR = std::remove_const_t<std::remove_reference_t<Type>>;
-
+  TVM_FFI_INLINE operator TypeWithoutCR() {  // 
NOLINT(google-explicit-constructor)
     if constexpr (std::is_same_v<TypeWithoutCR, AnyView>) {
       return args_[arg_index_];
     } else if constexpr (std::is_same_v<TypeWithoutCR, Any>) {
       return Any(args_[arg_index_]);
     } else {
-      std::optional<TypeWithoutCR> opt = 
args_[arg_index_].try_cast<TypeWithoutCR>();
+      std::optional<TypeWithoutCR> opt = args_[arg_index_].template 
try_cast<TypeWithoutCR>();
       if (!opt.has_value()) {
         TVMFFIAny any_data = args_[arg_index_].CopyToTVMFFIAny();
         TVM_FFI_THROW(TypeError) << "Mismatched type on argument #" << 
arg_index_
@@ -187,6 +202,7 @@ TVM_FFI_INLINE void unpack_call(std::index_sequence<Is...>, 
const std::string* o
                                 const F& f, [[maybe_unused]] const AnyView* 
args,
                                 [[maybe_unused]] int32_t num_args, 
[[maybe_unused]] Any* rv) {
   using FuncInfo = FunctionInfo<F>;
+  using PackedArgs = typename FuncInfo::ArgType;
   FGetFuncSignature f_sig = FuncInfo::Sig;
 
   // somehow MSVC does not support the static constexpr member in this case, 
function is fine
@@ -202,9 +218,10 @@ TVM_FFI_INLINE void 
unpack_call(std::index_sequence<Is...>, const std::string* o
   }
   // use index sequence to do recursive-less unpacking
   if constexpr (std::is_same_v<R, void>) {
-    f(ArgValueWithContext(args, Is, optional_name, f_sig)...);
+    f(ArgValueWithContext<std::tuple_element_t<Is, PackedArgs>>{args, Is, 
optional_name, f_sig}...);
   } else {
-    *rv = R(f(ArgValueWithContext(args, Is, optional_name, f_sig)...));
+    *rv = R(f(ArgValueWithContext<std::tuple_element_t<Is, PackedArgs>>{args, 
Is, optional_name,
+                                                                        
f_sig}...));
   }
 }
 

Reply via email to