Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion cpp2rust/converter/models/converter_refcount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<clang::DeclRefExpr>(inner) &&

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this entire check is focusing only on DeclRefExpr, while missing other AST shapes

The correct solution is probably to do computed_expr_type_ = ComputedExprType::FreshPointer in ConvertFunctionToFunctionPointer

Then the check in VisitExplicitCastExpr becomes: !TypeIsCopyable(sub->getType()) && !isFresh()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #290

inner->getType()->isFunctionPointerType();
if (!TypeIsCopyable(expr->getSubExpr()->getType()) &&
(!expr->getSubExpr()->getType()->isFunctionPointerType() ||
is_fn_ptr_var_ref)) {
StrCat(".clone()");
}
return false;
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/out/refcount/void_cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<fn() -> i32>::new(bump_and_return_4)).clone();
(FnPtr::<fn() -> i32>::new(bump_and_return_4));
assert!(((*side_effect_counter_3.with(Value::clone).borrow()) == 2));
((FnPtr::<fn() -> i32>::new(bump_and_return_4)).cast::<fn() -> i32>(None)).clone();
((FnPtr::<fn() -> i32>::new(bump_and_return_4)).cast::<fn() -> i32>(None));
assert!(((*side_effect_counter_3.with(Value::clone).borrow()) == 2));
let storage: Value<i32> = Rc::new(RefCell::new(11));
let p: Value<Ptr<i32>> = Rc::new(RefCell::new((storage.as_pointer())));
Expand Down
Loading