diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 9bee3eb9..d66f485a 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -1322,7 +1322,15 @@ bool ConverterRefCount::VisitExplicitCastExpr(clang::ExplicitCastExpr *expr) { if (expr->getTypeAsWritten()->isVoidType()) { PushExprKind push(*this, ExprKind::Void); Convert(expr->getSubExpr()); - if (!TypeIsCopyable(expr->getSubExpr()->getType())) { + // Skip .clone() for fresh fn-ptr values (cast/constructor results). + // Variable references to fn-ptrs still need .clone() because FnPtr is + // non-Copy and (*var.borrow()) would otherwise attempt a move. + auto *inner = expr->getSubExpr()->IgnoreParenImpCasts(); + bool is_fn_ptr_var_ref = clang::isa(inner) && + inner->getType()->isFunctionPointerType(); + if (!TypeIsCopyable(expr->getSubExpr()->getType()) && + (!expr->getSubExpr()->getType()->isFunctionPointerType() || + is_fn_ptr_var_ref)) { StrCat(".clone()"); } return false; diff --git a/tests/unit/out/refcount/void_cast.rs b/tests/unit/out/refcount/void_cast.rs index 77724cab..a4ae9f32 100644 --- a/tests/unit/out/refcount/void_cast.rs +++ b/tests/unit/out/refcount/void_cast.rs @@ -106,9 +106,9 @@ fn main_0() -> i32 { assert!(((*chosen.borrow()) == 123)); bump_and_return_4.clone(); assert!(((*side_effect_counter_3.with(Value::clone).borrow()) == 2)); - (FnPtr:: i32>::new(bump_and_return_4)).clone(); + (FnPtr:: i32>::new(bump_and_return_4)); assert!(((*side_effect_counter_3.with(Value::clone).borrow()) == 2)); - ((FnPtr:: i32>::new(bump_and_return_4)).cast:: i32>(None)).clone(); + ((FnPtr:: i32>::new(bump_and_return_4)).cast:: i32>(None)); assert!(((*side_effect_counter_3.with(Value::clone).borrow()) == 2)); let storage: Value = Rc::new(RefCell::new(11)); let p: Value> = Rc::new(RefCell::new((storage.as_pointer())));