Skip to content

Commit

Permalink
analyze: mir_op: avoid moving Option<&mut [T]> for offset calls
Browse files Browse the repository at this point in the history
  • Loading branch information
spernsteiner committed Dec 2, 2024
1 parent 684894f commit 839571e
Showing 1 changed file with 57 additions and 1 deletion.
58 changes: 57 additions & 1 deletion c2rust-analyze/src/rewrite/expr/mir_op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,7 @@ impl<'a, 'tcx> ExprRewriteVisitor<'a, 'tcx> {

// Normal case: just `visit_rvalue` and emit a cast if needed.
v.visit_rvalue(rv, Some(rv_lty));
v.emit_cast_lty_lty(rv_lty, pl_lty, cast_can_move)
v.emit_cast_lty_lty_or_borrow(rv_lty, pl_lty, cast_can_move)
});
self.enter_dest(|v| v.visit_place(pl, PlaceAccess::Mut, RequireSinglePointer::Yes));
}
Expand Down Expand Up @@ -1376,6 +1376,20 @@ impl<'a, 'tcx> ExprRewriteVisitor<'a, 'tcx> {
builder.build_cast_lty_lty(from_lty, to_lty);
}

fn emit_cast_lty_lty_or_borrow(
&mut self,
from_lty: LTy<'tcx>,
to_lty: LTy<'tcx>,
cast_can_move: bool,
) {
let perms = self.perms;
let flags = self.flags;
let mut builder = CastBuilder::new(self.acx.tcx(), perms, flags, |rk| self.emit(rk))
.can_move(cast_can_move)
.borrow(true);
builder.build_cast_lty_lty(from_lty, to_lty);
}

/// Cast `from_lty` to an adjusted version of itself. If `from_desc` is the `TypeDesc`
/// corresponding to `from_lty`, this emits a cast from `from_desc` to `to_adjust(from_desc)`.
fn emit_cast_lty_adjust(
Expand Down Expand Up @@ -1506,6 +1520,9 @@ pub struct CastBuilder<'a, 'tcx, PT1, PT2, F> {
/// `can_move` is set; the former moves out of `ptr` but avoids an additional borrow, making it
/// suitable to be used as the result expression of a function.
can_move: bool,
/// If set, the cast builder will emit a downgrade/borrow operation even for no-op casts, if
/// the thing being cast can't be moved (`!can_move`) and also can't be copied.
borrow: bool,
}

impl<'a, 'tcx, PT1, PT2, F> CastBuilder<'a, 'tcx, PT1, PT2, F>
Expand All @@ -1526,6 +1543,7 @@ where
flags,
emit,
can_move: false,
borrow: false,
}
}

Expand All @@ -1534,6 +1552,11 @@ where
self
}

pub fn borrow(mut self, borrow: bool) -> Self {
self.borrow = borrow;
self
}

pub fn build_cast_desc_desc(&mut self, from: TypeDesc<'tcx>, to: TypeDesc<'tcx>) {
self.try_build_cast_desc_desc(from, to).unwrap()
}
Expand Down Expand Up @@ -1565,6 +1588,39 @@ where
from.pointee_ty = to.pointee_ty;

if from == to {
// We normally do nothing if the `from` and `to` types are the same. However, in some
// cases we need to introduce a downgrade to avoid moving the operand inappropriately.
let can_reborrow = !from.option && !from.dyn_owned;
let need_downgrade = !self.can_move && !from.own.is_copy() && !can_reborrow;
if self.borrow && need_downgrade {
let mutbl = match from.own {
Ownership::Raw | Ownership::Imm | Ownership::Cell => false,
Ownership::RawMut | Ownership::Mut => true,
// Can't downgrade in these cases.
Ownership::Rc | Ownership::Box => return Ok(()),
};
if from.option {
(self.emit)(RewriteKind::OptionDowngrade {
mutbl,
kind: if from.dyn_owned {
OptionDowngradeKind::Borrow
} else {
OptionDowngradeKind::Deref
},
});
}
if from.dyn_owned {
if from.option {
(self.emit)(RewriteKind::OptionMapBegin);
(self.emit)(RewriteKind::Deref);
}
(self.emit)(RewriteKind::DynOwnedDowngrade { mutbl });
if from.option {
(self.emit)(RewriteKind::OptionMapEnd);
}
}
}

return Ok(());
}

Expand Down

0 comments on commit 839571e

Please sign in to comment.