Skip to content

Commit 3c8a146

Browse files
committed
Add move access type
1 parent 69dcba3 commit 3c8a146

8 files changed

Lines changed: 124 additions & 53 deletions

File tree

‎cpp2rust/converter/converter.cpp‎

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4614,8 +4614,8 @@ void Converter::PlaceholderCtx::dump() const {
46144614
<< ", is_cpp_ptr: " << is_cpp_ptr
46154615
<< ", maps_to_rust_ptr: " << maps_to_rust_ptr
46164616
<< ", declared_in_rule_as_rust_ptr: "
4617-
<< declared_in_rule_as_rust_ptr << ", access: "
4618-
<< (access == TranslationRule::Access::kRead ? "read" : "write")
4617+
<< declared_in_rule_as_rust_ptr
4618+
<< ", access: " << static_cast<int>(access)
46194619
<< ", param_type: " << param_type
46204620
<< ", materialize_idx: " << materialize_idx << '\n';
46214621
}
@@ -4653,10 +4653,10 @@ std::string Converter::ConvertPlaceholder(clang::Expr *expr, clang::Expr *arg,
46534653
if (ph_ctx.needs_object_receiver()) {
46544654
Buffer buf(*this);
46554655
PushExplicitAutoref autoref(
4656-
*this,
4657-
ph_ctx.is_index_base
4658-
? std::optional(ph_ctx.access == TranslationRule::Access::kWrite)
4659-
: std::nullopt);
4656+
*this, ph_ctx.is_index_base
4657+
? std::optional(ph_ctx.access ==
4658+
TranslationRule::Access::kBorrowMut)
4659+
: std::nullopt);
46604660
PushExprKind push(*this, ExprKind::RValue);
46614661
ConvertDeref(arg);
46624662
return std::move(buf).str();
@@ -4670,13 +4670,17 @@ std::string Converter::ConvertPlaceholder(clang::Expr *expr, clang::Expr *arg,
46704670
return ConvertLValue(arg);
46714671
}
46724672

4673-
if (ph_ctx.access == TranslationRule::Access::kMove) {
4673+
if (ph_ctx.access == TranslationRule::Access::kTake) {
46744674
if (clang::isa<clang::MaterializeTemporaryExpr>(arg)) {
46754675
return ConvertRValue(arg);
46764676
}
46774677
return std::format("std::mem::take(&mut {})", ConvertLValue(arg));
46784678
}
46794679

4680+
if (ph_ctx.access == TranslationRule::Access::kRead) {
4681+
return ConvertFreshRValue(arg, ph_ctx.implicit_convert_to);
4682+
}
4683+
46804684
return ConvertRValue(arg, ph_ctx.implicit_convert_to);
46814685
}
46824686

‎cpp2rust/converter/converter.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
251251
}
252252

253253
bool needs_lvalue() const {
254-
return access == TranslationRule::Access::kWrite;
254+
return access == TranslationRule::Access::kBorrowMut;
255255
}
256256

257257
void dump() const;

‎cpp2rust/converter/models/converter_refcount.cpp‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2584,7 +2584,8 @@ std::string ConverterRefCount::ConvertMappedMethodCall(
25842584
clang::Expr *expr, const TranslationRule::MethodCallFragment &mc,
25852585
clang::Expr **args, unsigned num_args, TempMaterializationCtx *ctx) {
25862586
auto receiver_ph = mc.getReceiverPlaceholder();
2587-
if (!receiver_ph || receiver_ph->access == TranslationRule::Access::kRead) {
2587+
if (!receiver_ph || receiver_ph->access == TranslationRule::Access::kBorrow ||
2588+
receiver_ph->access == TranslationRule::Access::kRead) {
25882589
return Converter::ConvertMappedMethodCall(expr, mc, args, num_args, ctx);
25892590
}
25902591

‎cpp2rust/converter/translation_rule.cpp‎

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,18 @@ TypeInfo ParseTypeInfoJSON(const llvm::json::Object &obj) {
3535
}
3636

3737
Access ParseAccessJSON(llvm::StringRef value) {
38-
if (value == "read") {
38+
if (value == "borrow") {
39+
return Access::kBorrow;
40+
} else if (value == "borrow_mut") {
41+
return Access::kBorrowMut;
42+
} else if (value == "read") {
3943
return Access::kRead;
40-
} else if (value == "write") {
41-
return Access::kWrite;
42-
} else if (value == "move") {
43-
return Access::kMove;
44+
} else if (value == "take") {
45+
return Access::kTake;
4446
} else {
4547
llvm::errs() << "Invalid access value: " << value << '\n';
4648
assert(0);
47-
return Access::kRead;
49+
return Access::kBorrow;
4850
}
4951
}
5052

@@ -247,14 +249,17 @@ void VaArgsFragment::dump() const { log() << " va_args\n"; }
247249
void PlaceholderFragment::dump() const {
248250
log() << " placeholder: " << n;
249251
switch (access) {
252+
case Access::kBorrow:
253+
log() << " (borrow)\n";
254+
break;
255+
case Access::kBorrowMut:
256+
log() << " (borrow_mut)\n";
257+
break;
250258
case Access::kRead:
251259
log() << " (read)\n";
252260
break;
253-
case Access::kWrite:
254-
log() << " (write)\n";
255-
break;
256-
case Access::kMove:
257-
log() << " (move)\n";
261+
case Access::kTake:
262+
log() << " (take)\n";
258263
break;
259264
}
260265
}

‎cpp2rust/converter/translation_rule.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ struct TextFragment {
2323
void dump() const;
2424
};
2525

26-
enum class Access : int8_t { kRead, kWrite, kMove };
26+
enum class Access : int8_t { kBorrow, kBorrowMut, kRead, kTake };
2727

2828
struct PlaceholderFragment {
2929
unsigned n; // "a0", "a1", ...

‎rule-preprocessor/src/ir.rs‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,12 @@ pub enum BodyFragment {
143143
}
144144

145145
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
146-
#[serde(rename_all = "lowercase")]
146+
#[serde(rename_all = "snake_case")]
147147
pub enum Access {
148+
Borrow,
149+
BorrowMut,
148150
Read,
149-
Write,
150-
Move,
151+
Take,
151152
Unknown,
152153
}
153154

‎rule-preprocessor/src/semantic.rs‎

Lines changed: 82 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ impl<'tcx> FnDecl<'tcx> {
193193
fn_ir,
194194
visited: HashMap::new(),
195195
};
196-
visitor.visit_expr(self.body.value, Access::Read);
196+
visitor.visit_expr(self.body.value, Access::Borrow);
197197
}
198198
}
199199

@@ -290,6 +290,21 @@ fn decl_source_file(
290290
)
291291
}
292292

293+
fn is_copy<'tcx>(tcx: rustc_middle::ty::TyCtxt<'tcx>, ty: rustc_middle::ty::Ty<'tcx>) -> bool {
294+
use rustc_infer::infer::TyCtxtInferExt;
295+
use rustc_trait_selection::infer::InferCtxtExt;
296+
297+
let Some(copy_trait) = tcx.lang_items().copy_trait() else {
298+
return false;
299+
};
300+
let infcx = tcx
301+
.infer_ctxt()
302+
.build(rustc_middle::ty::TypingMode::non_body_analysis());
303+
infcx
304+
.type_implements_trait(copy_trait, [ty], rustc_middle::ty::ParamEnv::empty())
305+
.must_apply_modulo_regions()
306+
}
307+
293308
fn type_derives<'tcx>(
294309
tcx: rustc_middle::ty::TyCtxt<'tcx>,
295310
ty: rustc_middle::ty::Ty<'tcx>,
@@ -353,10 +368,15 @@ impl<'a, 'tcx> AstVisitor<'a, 'tcx> {
353368
fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>, context: Access) {
354369
// Reached an argument used inside the rule body
355370
if let Some(param) = self.expr_as_decl_ref(expr) {
371+
let access = if context == Access::Borrow && self.is_moved(expr) {
372+
Access::Read
373+
} else {
374+
context
375+
};
356376
self.fn_ir
357377
.resolve_next_param(&param, &mut self.visited, |p| {
358378
if p.access == Access::Unknown {
359-
p.access = context;
379+
p.access = access;
360380
}
361381
});
362382
return;
@@ -370,53 +390,62 @@ impl<'a, 'tcx> AstVisitor<'a, 'tcx> {
370390
param_access.first().copied().unwrap_or(Access::Unknown),
371391
);
372392
for (i, arg) in args.iter().enumerate() {
373-
let access = param_access.get(i + 1).copied().unwrap_or(Access::Read);
393+
let access = param_access.get(i + 1).copied().unwrap_or(Access::Borrow);
374394
self.visit_expr(arg, access);
375395
}
376396
}
377397
rustc_hir::ExprKind::Call(callee, args) => {
378398
if self.is_std_mem_take(expr) && args.len() == 1 {
379-
self.visit_expr(&args[0], Access::Move);
399+
self.visit_expr(&args[0], Access::Take);
380400
} else {
381401
self.visit_expr(callee, context);
382402
let param_access = self.resolve_callee_param_access(expr);
383403
for (i, arg) in args.iter().enumerate() {
384-
let access = param_access.get(i).copied().unwrap_or(Access::Read);
404+
let access = param_access.get(i).copied().unwrap_or(Access::Borrow);
385405
self.visit_expr(arg, access);
386406
}
387407
}
388408
}
389409

390410
rustc_hir::ExprKind::Assign(lhs, rhs, _)
391411
| rustc_hir::ExprKind::AssignOp(_, lhs, rhs) => {
392-
self.visit_expr(lhs, Access::Write);
393-
self.visit_expr(rhs, Access::Read);
412+
self.visit_expr(lhs, Access::BorrowMut);
413+
self.visit_expr(rhs, Access::Borrow);
394414
}
395415

396416
rustc_hir::ExprKind::AddrOf(_, rustc_hir::Mutability::Mut, inner) => {
397417
self.visit_expr(
398418
inner,
399-
if context == Access::Move {
400-
Access::Move
419+
if context == Access::Take {
420+
Access::Take
401421
} else {
402-
Access::Write
422+
Access::BorrowMut
403423
},
404424
);
405425
}
406426
rustc_hir::ExprKind::AddrOf(_, rustc_hir::Mutability::Not, inner) => {
407-
self.visit_expr(inner, Access::Read);
427+
if let Some(param) = self.expr_as_decl_ref(inner) {
428+
self.fn_ir
429+
.resolve_next_param(&param, &mut self.visited, |p| {
430+
if p.access == Access::Unknown {
431+
p.access = Access::Borrow;
432+
}
433+
});
434+
return;
435+
}
436+
self.visit_expr(inner, Access::Borrow);
408437
}
409438

410439
rustc_hir::ExprKind::Block(block, _) | rustc_hir::ExprKind::Loop(block, _, _, _) => {
411440
for stmt in block.stmts {
412441
match &stmt.kind {
413442
rustc_hir::StmtKind::Let(local) => {
414443
if let Some(init) = local.init {
415-
self.visit_expr(init, Access::Read);
444+
self.visit_expr(init, Access::Borrow);
416445
}
417446
}
418447
rustc_hir::StmtKind::Expr(e) | rustc_hir::StmtKind::Semi(e) => {
419-
self.visit_expr(e, Access::Read);
448+
self.visit_expr(e, Access::Borrow);
420449
}
421450
_ => {}
422451
}
@@ -427,22 +456,36 @@ impl<'a, 'tcx> AstVisitor<'a, 'tcx> {
427456
}
428457

429458
rustc_hir::ExprKind::If(cond, then_branch, else_branch) => {
430-
self.visit_expr(cond, Access::Read);
459+
self.visit_expr(cond, Access::Borrow);
431460
self.visit_expr(then_branch, context);
432461
if let Some(e) = else_branch {
433462
self.visit_expr(e, context);
434463
}
435464
}
436465
rustc_hir::ExprKind::Match(scrutinee, arms, _) => {
437-
self.visit_expr(scrutinee, Access::Read);
466+
self.visit_expr(scrutinee, Access::Borrow);
438467
for arm in arms.iter() {
468+
if let Some(guard) = arm.guard {
469+
self.visit_expr(guard, Access::Borrow);
470+
}
439471
self.visit_expr(arm.body, context);
440472
}
441473
}
442474

475+
rustc_hir::ExprKind::Field(base, _) => {
476+
if let Some(param) = self.expr_as_decl_ref(base) {
477+
self.fn_ir
478+
.resolve_next_param(&param, &mut self.visited, |p| {
479+
if p.access == Access::Unknown {
480+
p.access = context;
481+
}
482+
});
483+
return;
484+
}
485+
self.visit_expr(base, context);
486+
}
443487
rustc_hir::ExprKind::Unary(_, e)
444488
| rustc_hir::ExprKind::Cast(e, _)
445-
| rustc_hir::ExprKind::Field(e, _)
446489
| rustc_hir::ExprKind::DropTemps(e)
447490
| rustc_hir::ExprKind::Repeat(e, _) => {
448491
self.visit_expr(e, context);
@@ -480,7 +523,7 @@ impl<'a, 'tcx> AstVisitor<'a, 'tcx> {
480523
| rustc_hir::ExprKind::Continue(_) => {}
481524

482525
rustc_hir::ExprKind::Ret(Some(e)) | rustc_hir::ExprKind::Break(_, Some(e)) => {
483-
self.visit_expr(e, Access::Read);
526+
self.visit_expr(e, Access::Borrow);
484527
}
485528

486529
other => {
@@ -494,6 +537,15 @@ impl<'a, 'tcx> AstVisitor<'a, 'tcx> {
494537
}
495538
}
496539

540+
fn is_moved(&self, expr: &rustc_hir::Expr<'tcx>) -> bool {
541+
let results = self.tcx.typeck(expr.hir_id.owner);
542+
let borrowed = results
543+
.expr_adjustments(expr)
544+
.iter()
545+
.any(|adj| matches!(adj.kind, rustc_middle::ty::adjustment::Adjust::Borrow(_)));
546+
!borrowed && !is_copy(self.tcx, results.expr_ty(expr))
547+
}
548+
497549
fn expr_as_decl_ref(&self, expr: &rustc_hir::Expr<'_>) -> Option<String> {
498550
if let rustc_hir::ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = &expr.kind
499551
&& let Some(seg) = path.segments.last()
@@ -548,11 +600,19 @@ impl<'a, 'tcx> AstVisitor<'a, 'tcx> {
548600

549601
fn access_for_type(ty: &rustc_middle::ty::Ty<'_>) -> Access {
550602
match ty.kind() {
551-
rustc_middle::ty::TyKind::Ref(_, _, rustc_middle::ty::Mutability::Mut) => Access::Write,
552-
rustc_middle::ty::TyKind::Ref(_, _, rustc_middle::ty::Mutability::Not) => Access::Read,
553-
rustc_middle::ty::TyKind::RawPtr(_, rustc_middle::ty::Mutability::Mut) => Access::Write,
554-
rustc_middle::ty::TyKind::RawPtr(_, rustc_middle::ty::Mutability::Not) => Access::Read,
555-
_ => Access::Read,
603+
rustc_middle::ty::TyKind::Ref(_, _, rustc_middle::ty::Mutability::Mut) => {
604+
Access::BorrowMut
605+
}
606+
rustc_middle::ty::TyKind::Ref(_, _, rustc_middle::ty::Mutability::Not) => {
607+
Access::Borrow
608+
}
609+
rustc_middle::ty::TyKind::RawPtr(_, rustc_middle::ty::Mutability::Mut) => {
610+
Access::BorrowMut
611+
}
612+
rustc_middle::ty::TyKind::RawPtr(_, rustc_middle::ty::Mutability::Not) => {
613+
Access::Borrow
614+
}
615+
_ => Access::Borrow,
556616
}
557617
}
558618
}

‎rule-preprocessor/src/syntactic.rs‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -405,15 +405,15 @@ impl<'a> FnIrBuilder<'a> {
405405
&& lhs.syntax().text_range().end()
406406
== name_ref.syntax().text_range().end()
407407
{
408-
return Some(Access::Write);
408+
return Some(Access::BorrowMut);
409409
}
410-
Some(Access::Read)
410+
Some(Access::Unknown)
411411
},
412412
ast::RefExpr(ref_expr) => {
413413
if ref_expr.mut_token().is_some() {
414-
Some(Access::Write)
414+
Some(Access::BorrowMut)
415415
} else {
416-
Some(Access::Read)
416+
Some(Access::Borrow)
417417
}
418418
},
419419
ast::MethodCallExpr(call) => {
@@ -435,16 +435,16 @@ impl<'a> FnIrBuilder<'a> {
435435
&& sl.tail_expr().is_some_and(|tail|
436436
tail.syntax().text_range() == name_ref.syntax().text_range())
437437
{
438-
Some(Access::Write)
438+
Some(Access::BorrowMut)
439439
} else {
440-
Some(Access::Read)
440+
Some(Access::Unknown)
441441
}
442442
},
443443
_ => None,
444444
}
445445
}
446446
})
447-
.unwrap_or(Access::Read)
447+
.unwrap_or(Access::Unknown)
448448
}
449449

450450
fn is_extern(&self) -> bool {

0 commit comments

Comments
 (0)