From c966e63e727d5b27ea593f3f1014826198cef756 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Mon, 4 May 2026 13:47:11 +0100 Subject: [PATCH 1/8] Add explicit reference for pointer dereferences that do autoreference --- cpp2rust/converter/converter.cpp | 67 +++++++++++++++++++++++++------- cpp2rust/converter/converter.h | 20 ++++++++++ 2 files changed, 72 insertions(+), 15 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index ea07e74..2fedd73 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1059,7 +1059,10 @@ void Converter::ConvertLoopVariable(clang::VarDecl *decl, StrCat(std::format(".as_mut_ptr().add({})", loop_var_name)); } } else { - Convert(range_init); + { + PushAutorefReceiver autoref(*this, /*is_mut=*/false); + Convert(range_init); + } StrCat(std::format("[{}]", loop_var_name)); StrCat(".clone()"); } @@ -2218,18 +2221,22 @@ void Converter::EmitStmtExprTail(clang::Expr *tail) { Convert(tail); } bool Converter::VisitConditionalOperator(clang::ConditionalOperator *expr) { StrCat(keyword::kIf); ConvertCondition(expr->getCond()); + bool branch_is_addr = + expr->isLValue() && !isRValue() && !expr->getType()->isFunctionType(); { PushBrace then_brace(*this); - if (expr->isLValue() && !isRValue() && !expr->getType()->isFunctionType()) { + if (branch_is_addr) { StrCat(token::kRef, keyword_mut_); + autoref_receiver_ = false; } Convert(expr->getTrueExpr()); } StrCat(keyword::kElse); { PushBrace else_brace(*this); - if (expr->isLValue() && !isRValue() && !expr->getType()->isFunctionType()) { + if (branch_is_addr) { StrCat(token::kRef, keyword_mut_); + autoref_receiver_ = false; } Convert(expr->getFalseExpr()); } @@ -2285,11 +2292,8 @@ bool Converter::VisitDeclRefExpr(clang::DeclRefExpr *expr) { if (decl->getType()->getAs() && !isAddrOf() && !map_iter_decls_.contains(clang::dyn_cast(decl))) { - { - PushParen paren(*this); - StrCat(GetPointerDerefPrefix(decl->getType().getNonReferenceType()), - std::move(str)); - } + EmitMaybeWrappedDeref(std::move(str), + decl->getType().getNonReferenceType()); SetValueFreshness(expr->getType()); return false; } @@ -2362,9 +2366,17 @@ bool Converter::ConvertCXXOperatorCallExpr(clang::CXXOperatorCallExpr *expr) { Convert(expr->getArg(0)); } break; - case clang::OverloadedOperatorKind::OO_Subscript: + case clang::OverloadedOperatorKind::OO_Subscript: { + bool is_mut = true; + if (auto *callee = expr->getDirectCallee()) { + if (auto *method = clang::dyn_cast(callee)) { + is_mut = !method->isConst(); + } + } + PushAutorefReceiver autoref(*this, is_mut); ConvertArraySubscript(expr->getArg(0), expr->getArg(1), expr->getType()); break; + } case clang::OverloadedOperatorKind::OO_LessLess: if (IsCallToOstream(expr)) { ConvertCallToOstream(expr); @@ -2430,8 +2442,8 @@ bool Converter::VisitMemberExpr(clang::MemberExpr *expr) { } if (!isAddrOf() && member->getType()->isReferenceType()) { - PushParen paren(*this); - StrCat(GetPointerDerefPrefix(member->getType().getNonReferenceType()), str); + EmitMaybeWrappedDeref(std::move(str), + member->getType().getNonReferenceType()); return false; } @@ -2459,6 +2471,11 @@ void Converter::ConvertMemberExpr(clang::MemberExpr *expr) { auto *base = expr->getBase(); bool base_is_this = clang::isa(base->IgnoreCasts()); PushExprKind push(*this, isLValue() ? ExprKind::LValue : ExprKind::RValue); + std::optional autoref; + if (auto *method = clang::dyn_cast(member); + method && !method->isStatic() && isCallee() && !base_is_this) { + autoref.emplace(*this, !method->isConst()); + } if (expr->isArrow() && !base_is_this) { ConvertArrow(base); } else { @@ -3200,10 +3217,15 @@ void Converter::ConvertPointerOffset(clang::Expr *base, clang::Expr *idx, void Converter::ConvertArraySubscript(clang::Expr *base, clang::Expr *idx, clang::QualType type) { + bool is_unique_ptr = IsUniquePtr(base->getType()); + if (is_unique_ptr) { + autoref_receiver_ = false; + } Convert(base->IgnoreImplicit()); - if (IsUniquePtr(base->getType())) { + if (is_unique_ptr) { StrCat(".as_mut().unwrap()"); } + autoref_receiver_ = false; PushBracket bracket(*this); { PushParen paren(*this); @@ -3509,11 +3531,26 @@ void Converter::ConvertAddrOf(clang::Expr *expr, clang::QualType pointer_type) { } } +void Converter::EmitMaybeWrappedDeref(std::string inner, + clang::QualType pointee_type) { + bool wrap = autoref_receiver_; + bool wrap_mut = autoref_receiver_mut_; + autoref_receiver_ = false; + if (wrap) { + StrCat("(", wrap_mut ? "&mut " : "&"); + } + { + PushParen paren(*this); + StrCat(GetPointerDerefPrefix(pointee_type), std::move(inner)); + } + if (wrap) { + StrCat(")"); + } +} + void Converter::ConvertDeref(clang::Expr *expr) { if (!isAddrOf()) { - PushParen paren(*this); - StrCat(GetPointerDerefPrefix(expr->getType()->getPointeeType()), - ToString(expr)); + EmitMaybeWrappedDeref(ToString(expr), expr->getType()->getPointeeType()); } else { Convert(expr); } diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 0719c0b..a52c1c9 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -474,6 +474,8 @@ class Converter : public clang::RecursiveASTVisitor { virtual void ConvertDeref(clang::Expr *expr); + void EmitMaybeWrappedDeref(std::string inner, clang::QualType pointee_type); + virtual void ConvertArrow(clang::Expr *expr); virtual void ConvertCast(clang::QualType qual_type); @@ -515,6 +517,24 @@ class Converter : public clang::RecursiveASTVisitor { clang::ASTContext &ctx_; clang::FunctionDecl *curr_function_ = nullptr; bool in_function_formals_ = false; + bool autoref_receiver_ = false; + bool autoref_receiver_mut_ = false; + + struct PushAutorefReceiver { + Converter &c; + bool prev_active; + bool prev_mut; + PushAutorefReceiver(Converter &c, bool is_mut) + : c(c), prev_active(c.autoref_receiver_), + prev_mut(c.autoref_receiver_mut_) { + c.autoref_receiver_ = true; + c.autoref_receiver_mut_ = is_mut; + } + ~PushAutorefReceiver() { + c.autoref_receiver_ = prev_active; + c.autoref_receiver_mut_ = prev_mut; + } + }; std::stack curr_for_inc_; std::stack curr_init_type_; From 4099462ce00b778c3198c104516c4ab4ada0ff67 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Mon, 4 May 2026 13:47:51 +0100 Subject: [PATCH 2/8] Update tests --- cpp2rust/converter/converter.cpp | 68 ++++++++++++--------------- cpp2rust/converter/converter.h | 23 ++++----- tests/lit/lit/formats/Cpp2RustTest.py | 2 +- tests/unit/out/unsafe/vector2.rs | 8 ++-- tests/unit/out/unsafe/vector3.rs | 2 +- 5 files changed, 44 insertions(+), 59 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 2fedd73..41f4591 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -9,6 +9,7 @@ #include #include +#include #include "compiler.h" #include "converter/converter_lib.h" @@ -1060,7 +1061,7 @@ void Converter::ConvertLoopVariable(clang::VarDecl *decl, } } else { { - PushAutorefReceiver autoref(*this, /*is_mut=*/false); + PushExplicitAutoref autoref(*this, /*is_mut=*/false); Convert(range_init); } StrCat(std::format("[{}]", loop_var_name)); @@ -2224,20 +2225,22 @@ bool Converter::VisitConditionalOperator(clang::ConditionalOperator *expr) { bool branch_is_addr = expr->isLValue() && !isRValue() && !expr->getType()->isFunctionType(); { - PushBrace then_brace(*this); + PushBrace brace(*this); if (branch_is_addr) { StrCat(token::kRef, keyword_mut_); - autoref_receiver_ = false; } + PushExplicitAutoref no_autoref(*this, branch_is_addr ? std::optional{} + : autoref_mut_); Convert(expr->getTrueExpr()); } StrCat(keyword::kElse); { - PushBrace else_brace(*this); + PushBrace brace(*this); if (branch_is_addr) { StrCat(token::kRef, keyword_mut_); - autoref_receiver_ = false; } + PushExplicitAutoref no_autoref(*this, branch_is_addr ? std::optional{} + : autoref_mut_); Convert(expr->getFalseExpr()); } return false; @@ -2292,8 +2295,7 @@ bool Converter::VisitDeclRefExpr(clang::DeclRefExpr *expr) { if (decl->getType()->getAs() && !isAddrOf() && !map_iter_decls_.contains(clang::dyn_cast(decl))) { - EmitMaybeWrappedDeref(std::move(str), - decl->getType().getNonReferenceType()); + EmitDeref(std::move(str), decl->getType().getNonReferenceType()); SetValueFreshness(expr->getType()); return false; } @@ -2373,7 +2375,7 @@ bool Converter::ConvertCXXOperatorCallExpr(clang::CXXOperatorCallExpr *expr) { is_mut = !method->isConst(); } } - PushAutorefReceiver autoref(*this, is_mut); + PushExplicitAutoref autoref(*this, is_mut); ConvertArraySubscript(expr->getArg(0), expr->getArg(1), expr->getType()); break; } @@ -2442,8 +2444,7 @@ bool Converter::VisitMemberExpr(clang::MemberExpr *expr) { } if (!isAddrOf() && member->getType()->isReferenceType()) { - EmitMaybeWrappedDeref(std::move(str), - member->getType().getNonReferenceType()); + EmitDeref(std::move(str), member->getType().getNonReferenceType()); return false; } @@ -2471,19 +2472,18 @@ void Converter::ConvertMemberExpr(clang::MemberExpr *expr) { auto *base = expr->getBase(); bool base_is_this = clang::isa(base->IgnoreCasts()); PushExprKind push(*this, isLValue() ? ExprKind::LValue : ExprKind::RValue); - std::optional autoref; - if (auto *method = clang::dyn_cast(member); - method && !method->isStatic() && isCallee() && !base_is_this) { - autoref.emplace(*this, !method->isConst()); - } + auto *method = clang::dyn_cast(member); + PushExplicitAutoref autoref(*this, method && !method->isStatic() && + isCallee() && !base_is_this + ? std::optional{!method->isConst()} + : autoref_mut_); if (expr->isArrow() && !base_is_this) { ConvertArrow(base); } else { Convert(base); } - if (auto *method = clang::dyn_cast(member); - method && IsOverloadedMethod(method)) { + if (method && IsOverloadedMethod(method)) { StrCat(token::kDot); StrCat(GetOverloadedFunctionName(method)); } else { @@ -3217,15 +3217,14 @@ void Converter::ConvertPointerOffset(clang::Expr *base, clang::Expr *idx, void Converter::ConvertArraySubscript(clang::Expr *base, clang::Expr *idx, clang::QualType type) { - bool is_unique_ptr = IsUniquePtr(base->getType()); - if (is_unique_ptr) { - autoref_receiver_ = false; - } - Convert(base->IgnoreImplicit()); - if (is_unique_ptr) { + if (IsUniquePtr(base->getType())) { + PushExplicitAutoref no_autoref(*this, std::nullopt); + Convert(base->IgnoreImplicit()); StrCat(".as_mut().unwrap()"); + } else { + Convert(base->IgnoreImplicit()); } - autoref_receiver_ = false; + PushExplicitAutoref no_autoref(*this, std::nullopt); PushBracket bracket(*this); { PushParen paren(*this); @@ -3531,26 +3530,19 @@ void Converter::ConvertAddrOf(clang::Expr *expr, clang::QualType pointer_type) { } } -void Converter::EmitMaybeWrappedDeref(std::string inner, - clang::QualType pointee_type) { - bool wrap = autoref_receiver_; - bool wrap_mut = autoref_receiver_mut_; - autoref_receiver_ = false; +void Converter::EmitDeref(std::string inner, clang::QualType pointee_type) { + auto wrap = std::exchange(autoref_mut_, std::nullopt); + PushParen outer(*this, wrap.has_value()); if (wrap) { - StrCat("(", wrap_mut ? "&mut " : "&"); - } - { - PushParen paren(*this); - StrCat(GetPointerDerefPrefix(pointee_type), std::move(inner)); - } - if (wrap) { - StrCat(")"); + StrCat(*wrap ? "&mut" : "&"); } + PushParen paren(*this); + StrCat(GetPointerDerefPrefix(pointee_type), std::move(inner)); } void Converter::ConvertDeref(clang::Expr *expr) { if (!isAddrOf()) { - EmitMaybeWrappedDeref(ToString(expr), expr->getType()->getPointeeType()); + EmitDeref(ToString(expr), expr->getType()->getPointeeType()); } else { Convert(expr); } diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index a52c1c9..b24d598 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -474,7 +474,7 @@ class Converter : public clang::RecursiveASTVisitor { virtual void ConvertDeref(clang::Expr *expr); - void EmitMaybeWrappedDeref(std::string inner, clang::QualType pointee_type); + void EmitDeref(std::string inner, clang::QualType pointee_type); virtual void ConvertArrow(clang::Expr *expr); @@ -517,23 +517,16 @@ class Converter : public clang::RecursiveASTVisitor { clang::ASTContext &ctx_; clang::FunctionDecl *curr_function_ = nullptr; bool in_function_formals_ = false; - bool autoref_receiver_ = false; - bool autoref_receiver_mut_ = false; + std::optional autoref_mut_; - struct PushAutorefReceiver { + struct PushExplicitAutoref { Converter &c; - bool prev_active; - bool prev_mut; - PushAutorefReceiver(Converter &c, bool is_mut) - : c(c), prev_active(c.autoref_receiver_), - prev_mut(c.autoref_receiver_mut_) { - c.autoref_receiver_ = true; - c.autoref_receiver_mut_ = is_mut; - } - ~PushAutorefReceiver() { - c.autoref_receiver_ = prev_active; - c.autoref_receiver_mut_ = prev_mut; + std::optional prev; + PushExplicitAutoref(Converter &c, std::optional v) + : c(c), prev(c.autoref_mut_) { + c.autoref_mut_ = v; } + ~PushExplicitAutoref() { c.autoref_mut_ = prev; } }; std::stack curr_for_inc_; std::stack curr_init_type_; diff --git a/tests/lit/lit/formats/Cpp2RustTest.py b/tests/lit/lit/formats/Cpp2RustTest.py index d414f57..c308a5e 100644 --- a/tests/lit/lit/formats/Cpp2RustTest.py +++ b/tests/lit/lit/formats/Cpp2RustTest.py @@ -29,7 +29,7 @@ def __init__(self): self.regex_translation_fail = re.compile(r"//\s*translation-fail\s*(?::\s*(.*))?$", re.MULTILINE) self.regex_nondet_result = re.compile(r"//\s*nondet-result\s*(?::\s*(.*))?$", re.MULTILINE) self.rust_version = read_rust_version() - os.environ['RUSTFLAGS'] = '-Awarnings -A dangerous-implicit-autorefs' + os.environ['RUSTFLAGS'] = '-Awarnings' def updateExpected(self, generated, expected_path): os.makedirs(os.path.dirname(expected_path), exist_ok=True) diff --git a/tests/unit/out/unsafe/vector2.rs b/tests/unit/out/unsafe/vector2.rs index 5b0cef6..ff578e4 100644 --- a/tests/unit/out/unsafe/vector2.rs +++ b/tests/unit/out/unsafe/vector2.rs @@ -14,15 +14,15 @@ pub unsafe fn fn_0(v: *mut Vec, mut v3: Vec) { v2.push(0); v2.push(1); v2.push(3); - x = (*v)[(2_u64) as usize]; + x = (&mut (*v))[(2_u64) as usize]; v2[(0_u64) as usize] = 1; (if true { &mut v3 } else { &mut (*v) })[(0_u64) as usize] = 7; v2 = (*v).clone(); - (*v4)[(1_u64) as usize] = 13; + (&mut (*v4))[(1_u64) as usize] = 13; assert!(((x) == (6))); assert!(((*((*v).first_mut().unwrap())) == (4))); - assert!((((*v)[(1_u64) as usize]) == (5))); - assert!((((*v)[(2_u64) as usize]) == (6))); + assert!((((&mut (*v))[(1_u64) as usize]) == (5))); + assert!((((&mut (*v))[(2_u64) as usize]) == (6))); assert!(((*((*v).last_mut().unwrap())) == (20))); assert!(((v2[(0_u64) as usize]) == (4))); assert!(((v2[(1_u64) as usize]) == (5))); diff --git a/tests/unit/out/unsafe/vector3.rs b/tests/unit/out/unsafe/vector3.rs index 3c5b2d3..8d079cd 100644 --- a/tests/unit/out/unsafe/vector3.rs +++ b/tests/unit/out/unsafe/vector3.rs @@ -35,7 +35,7 @@ unsafe fn main_0() -> i32 { 'loop_: for v2 in 0..(v.len()) { let mut v2 = v.as_mut_ptr().add(v2); 'loop_: for i in 0..((*v2).len()) { - let mut i = (*v2)[i].clone(); + let mut i = (&(*v2))[i].clone(); printf(b"%d\n\0".as_ptr() as *const i8, ((i) + (3))); } } From 5b60ce633d0f5b68eb482ac09476c360202eb93a Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Mon, 4 May 2026 14:47:29 +0100 Subject: [PATCH 3/8] Move IsMutatingCall in converter_lib --- cpp2rust/converter/converter.cpp | 16 +++++----------- cpp2rust/converter/converter_lib.cpp | 9 +++++++++ cpp2rust/converter/converter_lib.h | 2 ++ 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 41f4591..bf8b2f7 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -2225,21 +2225,21 @@ bool Converter::VisitConditionalOperator(clang::ConditionalOperator *expr) { bool branch_is_addr = expr->isLValue() && !isRValue() && !expr->getType()->isFunctionType(); { - PushBrace brace(*this); + PushBrace then_brace(*this); if (branch_is_addr) { StrCat(token::kRef, keyword_mut_); } - PushExplicitAutoref no_autoref(*this, branch_is_addr ? std::optional{} + PushExplicitAutoref no_autoref(*this, branch_is_addr ? std::nullopt : autoref_mut_); Convert(expr->getTrueExpr()); } StrCat(keyword::kElse); { - PushBrace brace(*this); + PushBrace else_brace(*this); if (branch_is_addr) { StrCat(token::kRef, keyword_mut_); } - PushExplicitAutoref no_autoref(*this, branch_is_addr ? std::optional{} + PushExplicitAutoref no_autoref(*this, branch_is_addr ? std::nullopt : autoref_mut_); Convert(expr->getFalseExpr()); } @@ -2369,13 +2369,7 @@ bool Converter::ConvertCXXOperatorCallExpr(clang::CXXOperatorCallExpr *expr) { } break; case clang::OverloadedOperatorKind::OO_Subscript: { - bool is_mut = true; - if (auto *callee = expr->getDirectCallee()) { - if (auto *method = clang::dyn_cast(callee)) { - is_mut = !method->isConst(); - } - } - PushExplicitAutoref autoref(*this, is_mut); + PushExplicitAutoref autoref(*this, IsMutatingCall(expr)); ConvertArraySubscript(expr->getArg(0), expr->getArg(1), expr->getType()); break; } diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 9b89c64..0b00050 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -156,6 +156,15 @@ bool IsMut(clang::QualType qual_type) { qual_type->getPointeeType().isConstQualified()); } +bool IsMutatingCall(const clang::CallExpr *expr) { + if (auto *callee = expr->getDirectCallee()) { + if (auto *method = clang::dyn_cast(callee)) { + return !method->isConst(); + } + } + return true; +} + bool IsOverloadedFunction(const clang::FunctionDecl *decl) { const auto *ctx = decl->getDeclContext(); const auto decl_name = decl->getDeclName(); diff --git a/cpp2rust/converter/converter_lib.h b/cpp2rust/converter/converter_lib.h index cf72201..6b1aa8e 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -45,6 +45,8 @@ bool IsUnsignedArithOp(const clang::BinaryOperator *expr); bool IsMut(clang::QualType qual_type); +bool IsMutatingCall(const clang::CallExpr *expr); + bool IsOverloadedFunction(const clang::FunctionDecl *decl); bool IsOverloadedMethod(const clang::CXXMethodDecl *decl); From 8dcd152e8ea9f74f31b12bf0b338fb51544995c5 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Mon, 4 May 2026 15:06:41 +0100 Subject: [PATCH 4/8] Add implicit autoref tests --- tests/unit/implicit_autoref.cpp | 36 ++++++++ tests/unit/out/refcount/implicit_autoref.rs | 94 +++++++++++++++++++++ tests/unit/out/unsafe/implicit_autoref.rs | 66 +++++++++++++++ 3 files changed, 196 insertions(+) create mode 100644 tests/unit/implicit_autoref.cpp create mode 100644 tests/unit/out/refcount/implicit_autoref.rs create mode 100644 tests/unit/out/unsafe/implicit_autoref.rs diff --git a/tests/unit/implicit_autoref.cpp b/tests/unit/implicit_autoref.cpp new file mode 100644 index 0000000..82d0f0e --- /dev/null +++ b/tests/unit/implicit_autoref.cpp @@ -0,0 +1,36 @@ +#include + +struct Counter { + int value = 0; + void bump() { ++value; } + int get() const { return value; } +}; + +struct Holder { + Counter c; + Counter &ref; + Holder(Counter &c) : ref(c) {} +}; + +void via_ref(Counter &r) { r.bump(); } + +int main() { + Counter c; + Counter *p = &c; + (*p).bump(); + p->bump(); + + Counter arr[2]; + arr[0].bump(); + arr[1].bump(); + + Holder h(c); + h.c.bump(); + h.ref.bump(); + + via_ref(c); + + int sum = (*p).get() + h.c.get() + h.ref.get() + arr[0].get() + arr[1].get(); + printf("%d\n", sum); + return 0; +} diff --git a/tests/unit/out/refcount/implicit_autoref.rs b/tests/unit/out/refcount/implicit_autoref.rs new file mode 100644 index 0000000..ecf0a96 --- /dev/null +++ b/tests/unit/out/refcount/implicit_autoref.rs @@ -0,0 +1,94 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +#[derive(Default)] +pub struct Counter { + pub value: Value, +} +impl Counter { + pub fn bump(&self) { + (*self.value.borrow_mut()).prefix_inc(); + } + pub fn get(&self) -> i32 { + return (*self.value.borrow()); + } +} +impl Clone for Counter { + fn clone(&self) -> Self { + let mut this = Self { + value: Rc::new(RefCell::new((*self.value.borrow()))), + }; + this + } +} +impl ByteRepr for Counter {} +#[derive(Default)] +pub struct Holder { + pub c: Value, + pub ref_: Ptr, +} +impl Holder { + pub fn Holder(c: Ptr) -> Self { + let mut this = Self { + c: Rc::new(RefCell::new(::default())), + ref_: (c).clone(), + }; + this + } +} +impl Clone for Holder { + fn clone(&self) -> Self { + let mut this = Self { + c: Rc::new(RefCell::new((*self.c.borrow()).clone())), + ref_: (self.ref_).clone(), + }; + this + } +} +impl ByteRepr for Holder {} +pub fn via_ref_0(r: Ptr) { + ({ (*r.upgrade().deref()).bump() }); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let c: Value = Rc::new(RefCell::new(::default())); + let p: Value> = Rc::new(RefCell::new((c.as_pointer()))); + ({ (*(*p.borrow()).upgrade().deref()).bump() }); + ({ (*(*p.borrow()).upgrade().deref()).bump() }); + let arr: Value> = Rc::new(RefCell::new( + (0..2) + .map(|_| ::default()) + .collect::>(), + )); + ({ (*arr.borrow())[(0) as usize].bump() }); + ({ (*arr.borrow())[(1) as usize].bump() }); + let h: Value = Rc::new(RefCell::new(Holder::Holder(c.as_pointer()))); + ({ (*(*h.borrow()).c.borrow()).bump() }); + ({ (*(*h.borrow()).ref_.upgrade().deref()).bump() }); + ({ + let _r: Ptr = c.as_pointer(); + via_ref_0(_r) + }); + let sum: Value = Rc::new(RefCell::new({ + let _lhs = { + let _lhs = { + let _lhs = { + let _lhs = ({ (*(*p.borrow()).upgrade().deref()).get() }); + _lhs + ({ (*(*h.borrow()).c.borrow()).get() }) + }; + _lhs + ({ (*(*h.borrow()).ref_.upgrade().deref()).get() }) + }; + _lhs + ({ (*arr.borrow())[(0) as usize].get() }) + }; + _lhs + ({ (*arr.borrow())[(1) as usize].get() }) + })); + println!("{}", (*sum.borrow())); + return 0; +} diff --git a/tests/unit/out/unsafe/implicit_autoref.rs b/tests/unit/out/unsafe/implicit_autoref.rs new file mode 100644 index 0000000..7655164 --- /dev/null +++ b/tests/unit/out/unsafe/implicit_autoref.rs @@ -0,0 +1,66 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct Counter { + pub value: i32, +} +impl Counter { + pub unsafe fn bump(&mut self) { + self.value.prefix_inc(); + } + pub unsafe fn get(&self) -> i32 { + return self.value; + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct Holder { + pub c: Counter, + pub ref_: *mut Counter, +} +impl Holder { + pub unsafe fn Holder(c: *mut Counter) -> Self { + let mut this = Self { + c: ::default(), + ref_: c, + }; + this + } +} +pub unsafe fn via_ref_0(r: *mut Counter) { + (unsafe { (*r).bump() }); +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut c: Counter = ::default(); + let mut p: *mut Counter = (&mut c as *mut Counter); + (unsafe { (*p).bump() }); + (unsafe { (*p).bump() }); + let mut arr: [Counter; 2] = [::default(); 2]; + (unsafe { arr[(0) as usize].bump() }); + (unsafe { arr[(1) as usize].bump() }); + let mut h: Holder = Holder::Holder(&mut c as *mut Counter); + (unsafe { h.c.bump() }); + (unsafe { (*h.ref_).bump() }); + (unsafe { + let _r: *mut Counter = &mut c as *mut Counter; + via_ref_0(_r) + }); + let mut sum: i32 = (((((unsafe { (*p).get() }) + (unsafe { h.c.get() })) + + (unsafe { (*h.ref_).get() })) + + (unsafe { arr[(0) as usize].get() })) + + (unsafe { arr[(1) as usize].get() })); + printf(b"%d\n\0".as_ptr() as *const i8, sum); + return 0; +} From 31aa0f7e4416a3a906e0f691d3cf337a52c1d166 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Mon, 4 May 2026 15:21:02 +0100 Subject: [PATCH 5/8] Change printf to assert --- tests/unit/implicit_autoref.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/implicit_autoref.cpp b/tests/unit/implicit_autoref.cpp index 82d0f0e..ca4e84f 100644 --- a/tests/unit/implicit_autoref.cpp +++ b/tests/unit/implicit_autoref.cpp @@ -1,4 +1,4 @@ -#include +#include struct Counter { int value = 0; @@ -31,6 +31,6 @@ int main() { via_ref(c); int sum = (*p).get() + h.c.get() + h.ref.get() + arr[0].get() + arr[1].get(); - printf("%d\n", sum); + assert(sum == 11); return 0; } From 2f7134532154aecab6290cbc0f7c12bc83f79dad Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Mon, 4 May 2026 15:43:47 +0100 Subject: [PATCH 6/8] Simplify condition --- cpp2rust/converter/converter.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index bf8b2f7..019d9ad 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -2466,17 +2466,13 @@ void Converter::ConvertMemberExpr(clang::MemberExpr *expr) { auto *base = expr->getBase(); bool base_is_this = clang::isa(base->IgnoreCasts()); PushExprKind push(*this, isLValue() ? ExprKind::LValue : ExprKind::RValue); - auto *method = clang::dyn_cast(member); - PushExplicitAutoref autoref(*this, method && !method->isStatic() && - isCallee() && !base_is_this - ? std::optional{!method->isConst()} - : autoref_mut_); if (expr->isArrow() && !base_is_this) { ConvertArrow(base); } else { Convert(base); } + auto *method = clang::dyn_cast(member); if (method && IsOverloadedMethod(method)) { StrCat(token::kDot); StrCat(GetOverloadedFunctionName(method)); From f52bc69f3b34c2aa4254b098b6800b6bff18457b Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Mon, 4 May 2026 15:43:58 +0100 Subject: [PATCH 7/8] Update tests --- tests/unit/implicit_autoref.cpp | 49 ++++----- tests/unit/out/refcount/implicit_autoref.rs | 107 +++++++------------- tests/unit/out/unsafe/implicit_autoref.rs | 65 ++++-------- 3 files changed, 78 insertions(+), 143 deletions(-) diff --git a/tests/unit/implicit_autoref.cpp b/tests/unit/implicit_autoref.cpp index ca4e84f..78f0b7b 100644 --- a/tests/unit/implicit_autoref.cpp +++ b/tests/unit/implicit_autoref.cpp @@ -1,36 +1,29 @@ #include - -struct Counter { - int value = 0; - void bump() { ++value; } - int get() const { return value; } -}; +#include struct Holder { - Counter c; - Counter &ref; - Holder(Counter &c) : ref(c) {} + std::vector v; }; -void via_ref(Counter &r) { r.bump(); } - int main() { - Counter c; - Counter *p = &c; - (*p).bump(); - p->bump(); - - Counter arr[2]; - arr[0].bump(); - arr[1].bump(); - - Holder h(c); - h.c.bump(); - h.ref.bump(); - - via_ref(c); - - int sum = (*p).get() + h.c.get() + h.ref.get() + arr[0].get() + arr[1].get(); - assert(sum == 11); + std::vector v; + v.push_back(10); + v.push_back(20); + + std::vector *p = &v; + int a = (*p)[0]; + (*p)[1] = 30; + + Holder h; + h.v.push_back(40); + h.v.push_back(50); + Holder *hp = &h; + int b = (*hp).v[0]; + (*hp).v[1] = 60; + + assert(a == 10); + assert((*p)[1] == 30); + assert(b == 40); + assert((*hp).v[1] == 60); return 0; } diff --git a/tests/unit/out/refcount/implicit_autoref.rs b/tests/unit/out/refcount/implicit_autoref.rs index ecf0a96..61e1583 100644 --- a/tests/unit/out/refcount/implicit_autoref.rs +++ b/tests/unit/out/refcount/implicit_autoref.rs @@ -7,88 +7,59 @@ use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; #[derive(Default)] -pub struct Counter { - pub value: Value, -} -impl Counter { - pub fn bump(&self) { - (*self.value.borrow_mut()).prefix_inc(); - } - pub fn get(&self) -> i32 { - return (*self.value.borrow()); - } -} -impl Clone for Counter { - fn clone(&self) -> Self { - let mut this = Self { - value: Rc::new(RefCell::new((*self.value.borrow()))), - }; - this - } -} -impl ByteRepr for Counter {} -#[derive(Default)] pub struct Holder { - pub c: Value, - pub ref_: Ptr, -} -impl Holder { - pub fn Holder(c: Ptr) -> Self { - let mut this = Self { - c: Rc::new(RefCell::new(::default())), - ref_: (c).clone(), - }; - this - } + pub v: Value>, } impl Clone for Holder { fn clone(&self) -> Self { let mut this = Self { - c: Rc::new(RefCell::new((*self.c.borrow()).clone())), - ref_: (self.ref_).clone(), + v: Rc::new(RefCell::new((*self.v.borrow()).clone())), }; this } } impl ByteRepr for Holder {} -pub fn via_ref_0(r: Ptr) { - ({ (*r.upgrade().deref()).bump() }); -} pub fn main() { std::process::exit(main_0()); } fn main_0() -> i32 { - let c: Value = Rc::new(RefCell::new(::default())); - let p: Value> = Rc::new(RefCell::new((c.as_pointer()))); - ({ (*(*p.borrow()).upgrade().deref()).bump() }); - ({ (*(*p.borrow()).upgrade().deref()).bump() }); - let arr: Value> = Rc::new(RefCell::new( - (0..2) - .map(|_| ::default()) - .collect::>(), + let v: Value> = Rc::new(RefCell::new(Vec::new())); + (*v.borrow_mut()).push(10); + (*v.borrow_mut()).push(20); + let p: Value>> = Rc::new(RefCell::new((v.as_pointer()))); + let a: Value = Rc::new(RefCell::new( + ((((*p.borrow()).to_strong().as_pointer()) as Ptr) + .offset(0_u64 as isize) + .read()), )); - ({ (*arr.borrow())[(0) as usize].bump() }); - ({ (*arr.borrow())[(1) as usize].bump() }); - let h: Value = Rc::new(RefCell::new(Holder::Holder(c.as_pointer()))); - ({ (*(*h.borrow()).c.borrow()).bump() }); - ({ (*(*h.borrow()).ref_.upgrade().deref()).bump() }); - ({ - let _r: Ptr = c.as_pointer(); - via_ref_0(_r) - }); - let sum: Value = Rc::new(RefCell::new({ - let _lhs = { - let _lhs = { - let _lhs = { - let _lhs = ({ (*(*p.borrow()).upgrade().deref()).get() }); - _lhs + ({ (*(*h.borrow()).c.borrow()).get() }) - }; - _lhs + ({ (*(*h.borrow()).ref_.upgrade().deref()).get() }) - }; - _lhs + ({ (*arr.borrow())[(0) as usize].get() }) - }; - _lhs + ({ (*arr.borrow())[(1) as usize].get() }) - })); - println!("{}", (*sum.borrow())); + (((*p.borrow()).to_strong().as_pointer()) as Ptr) + .offset(1_u64 as isize) + .write(30); + let h: Value = Rc::new(RefCell::new(::default())); + (*(*h.borrow()).v.borrow_mut()).push(40); + (*(*h.borrow()).v.borrow_mut()).push(50); + let hp: Value> = Rc::new(RefCell::new((h.as_pointer()))); + let b: Value = Rc::new(RefCell::new( + (((*(*hp.borrow()).upgrade().deref()).v.as_pointer() as Ptr) + .offset(0_u64 as isize) + .read()), + )); + ((*(*hp.borrow()).upgrade().deref()).v.as_pointer() as Ptr) + .offset(1_u64 as isize) + .write(60); + assert!(((*a.borrow()) == 10)); + assert!( + (((((*p.borrow()).to_strong().as_pointer()) as Ptr) + .offset(1_u64 as isize) + .read()) + == 30) + ); + assert!(((*b.borrow()) == 40)); + assert!( + ((((*(*hp.borrow()).upgrade().deref()).v.as_pointer() as Ptr) + .offset(1_u64 as isize) + .read()) + == 60) + ); return 0; } diff --git a/tests/unit/out/unsafe/implicit_autoref.rs b/tests/unit/out/unsafe/implicit_autoref.rs index 7655164..709b4ec 100644 --- a/tests/unit/out/unsafe/implicit_autoref.rs +++ b/tests/unit/out/unsafe/implicit_autoref.rs @@ -7,35 +7,9 @@ use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; #[repr(C)] -#[derive(Copy, Clone, Default)] -pub struct Counter { - pub value: i32, -} -impl Counter { - pub unsafe fn bump(&mut self) { - self.value.prefix_inc(); - } - pub unsafe fn get(&self) -> i32 { - return self.value; - } -} -#[repr(C)] -#[derive(Copy, Clone, Default)] +#[derive(Clone, Default)] pub struct Holder { - pub c: Counter, - pub ref_: *mut Counter, -} -impl Holder { - pub unsafe fn Holder(c: *mut Counter) -> Self { - let mut this = Self { - c: ::default(), - ref_: c, - }; - this - } -} -pub unsafe fn via_ref_0(r: *mut Counter) { - (unsafe { (*r).bump() }); + pub v: Vec, } pub fn main() { unsafe { @@ -43,24 +17,21 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - let mut c: Counter = ::default(); - let mut p: *mut Counter = (&mut c as *mut Counter); - (unsafe { (*p).bump() }); - (unsafe { (*p).bump() }); - let mut arr: [Counter; 2] = [::default(); 2]; - (unsafe { arr[(0) as usize].bump() }); - (unsafe { arr[(1) as usize].bump() }); - let mut h: Holder = Holder::Holder(&mut c as *mut Counter); - (unsafe { h.c.bump() }); - (unsafe { (*h.ref_).bump() }); - (unsafe { - let _r: *mut Counter = &mut c as *mut Counter; - via_ref_0(_r) - }); - let mut sum: i32 = (((((unsafe { (*p).get() }) + (unsafe { h.c.get() })) - + (unsafe { (*h.ref_).get() })) - + (unsafe { arr[(0) as usize].get() })) - + (unsafe { arr[(1) as usize].get() })); - printf(b"%d\n\0".as_ptr() as *const i8, sum); + let mut v: Vec = Vec::new(); + v.push(10); + v.push(20); + let mut p: *mut Vec = (&mut v as *mut Vec); + let mut a: i32 = (&mut (*p))[(0_u64) as usize]; + (&mut (*p))[(1_u64) as usize] = 30; + let mut h: Holder = ::default(); + h.v.push(40); + h.v.push(50); + let mut hp: *mut Holder = (&mut h as *mut Holder); + let mut b: i32 = (&mut (*hp)).v[(0_u64) as usize]; + (&mut (*hp)).v[(1_u64) as usize] = 60; + assert!(((a) == (10))); + assert!((((&mut (*p))[(1_u64) as usize]) == (30))); + assert!(((b) == (40))); + assert!((((&mut (*hp)).v[(1_u64) as usize]) == (60))); return 0; } From fd5fdd67fbe9c3e0ac4766dd4ad9025eeb9747ef Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Mon, 4 May 2026 15:52:36 +0100 Subject: [PATCH 8/8] Revert if --- cpp2rust/converter/converter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 019d9ad..45c600f 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -2472,8 +2472,8 @@ void Converter::ConvertMemberExpr(clang::MemberExpr *expr) { Convert(base); } - auto *method = clang::dyn_cast(member); - if (method && IsOverloadedMethod(method)) { + if (auto *method = clang::dyn_cast(member); + method && IsOverloadedMethod(method)) { StrCat(token::kDot); StrCat(GetOverloadedFunctionName(method)); } else {