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 daf594da fix: preserve lvalues in UnchangedOr value access (#793)
daf594da is described below

commit daf594da8e6950fdc02ae35fcf4e0ab2e59a4979
Author: Tianqi Chen <[email protected]>
AuthorDate: Tue Sep 15 07:33:32 2026 -0400

    fix: preserve lvalues in UnchangedOr value access (#793)
    
    Remove the mutable-lvalue ValueOrUnchanged overload so lvalues use the
    borrowing const-reference overload; ownership transfer requires an
    explicit rvalue. Clarify the accessor documentation and add a focused
    lvalue-preservation regression test. Existing callers already express
    intentional transfers explicitly.
---
 include/tvm/ffi/extra/structural_mutate.h | 14 +++-----------
 tests/cpp/extra/test_structural_mutate.cc |  7 +++++++
 2 files changed, 10 insertions(+), 11 deletions(-)

diff --git a/include/tvm/ffi/extra/structural_mutate.h 
b/include/tvm/ffi/extra/structural_mutate.h
index c8bc0178..d3e59514 100644
--- a/include/tvm/ffi/extra/structural_mutate.h
+++ b/include/tvm/ffi/extra/structural_mutate.h
@@ -300,21 +300,12 @@ class UnchangedOr {
     return IsUnchanged() || data_.same_as(original);
   }
 
-  /*!
-   * \brief Move the replacement, or move \p original when unchanged.
-   * \param original The owned original value.
-   * \return The replacement or original value.
-   * \note Passing a named lvalue transfers ownership and may leave it 
moved-from.
-   */
-  TVM_FFI_INLINE T ValueOrUnchanged(T& original) && {
-    return IsUnchanged() ? std::move(original)
-                         : 
details::AnyUnsafe::MoveFromAnyAfterCheck<T>(std::move(data_));
-  }
-
   /*!
    * \brief Move the replacement, or copy \p original when unchanged.
    * \param original The borrowed original value, which is left unmodified.
    * \return The replacement or original value.
+   * \note Both mutable and const lvalues are borrowed. Use 
std::move(original) to transfer
+   * ownership.
    */
   TVM_FFI_INLINE T ValueOrUnchanged(const T& original) && {
     return IsUnchanged() ? original
@@ -325,6 +316,7 @@ class UnchangedOr {
    * \brief Move the replacement, or move \p original when unchanged.
    * \param original The owned original value.
    * \return The replacement or original value.
+   * \note The original is moved from only when the result is unchanged.
    */
   TVM_FFI_INLINE T ValueOrUnchanged(T&& original) && {
     return IsUnchanged() ? std::move(original)
diff --git a/tests/cpp/extra/test_structural_mutate.cc 
b/tests/cpp/extra/test_structural_mutate.cc
index 4222eac0..1debe194 100644
--- a/tests/cpp/extra/test_structural_mutate.cc
+++ b/tests/cpp/extra/test_structural_mutate.cc
@@ -72,6 +72,13 @@ TEST(UnchangedOr, PairedCasts) {
   
EXPECT_TRUE(UnchangedOr<Any>(Unchanged()).as_or_throw<UnchangedOr<TInt>>().IsUnchanged());
 }
 
+TEST(UnchangedOr, ValueOrUnchangedBorrowsLvalues) {
+  TInt original(7);
+  TInt result = UnchangedOr<TInt>(Unchanged()).ValueOrUnchanged(original);
+  EXPECT_TRUE(result.same_as(original));
+  EXPECT_EQ(original.use_count(), 2);
+}
+
 TEST(UnchangedOr, ConversionsAndAssignmentMacro) {
   static_assert(!std::is_convertible_v<UnchangedOr<Any>, UnchangedOr<int>>);
   static_assert(type_subsumes_v<Expected<UnchangedOr<TNumber>>, 
Expected<UnchangedOr<TInt>>>);

Reply via email to