2022-12-13 04:22:47 -08:00
|
|
|
use std::borrow::Cow;
|
2024-07-29 08:13:50 +10:00
|
|
|
|
2025-01-07 15:19:05 +00:00
|
|
|
use rustc_index::bit_set::DenseBitSet;
|
2020-06-08 14:50:39 -07:00
|
|
|
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
|
2020-03-29 16:41:09 +02:00
|
|
|
use rustc_middle::mir::*;
|
2023-05-06 14:13:12 +00:00
|
|
|
|
|
|
|
|
use super::MaybeBorrowedLocals;
|
2024-10-10 11:46:29 +11:00
|
|
|
use crate::{Analysis, GenKill, ResultsCursor};
|
2023-05-06 14:13:12 +00:00
|
|
|
|
2024-11-22 17:52:02 +11:00
|
|
|
/// The set of locals in a MIR body that do not have `StorageLive`/`StorageDead` annotations.
|
|
|
|
|
///
|
|
|
|
|
/// These locals have fixed storage for the duration of the body.
|
2025-01-07 15:19:05 +00:00
|
|
|
pub fn always_storage_live_locals(body: &Body<'_>) -> DenseBitSet<Local> {
|
|
|
|
|
let mut always_live_locals = DenseBitSet::new_filled(body.local_decls.len());
|
2024-11-22 17:52:02 +11:00
|
|
|
|
|
|
|
|
for block in &*body.basic_blocks {
|
|
|
|
|
for statement in &block.statements {
|
|
|
|
|
if let StatementKind::StorageLive(l) | StatementKind::StorageDead(l) = statement.kind {
|
|
|
|
|
always_live_locals.remove(l);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
always_live_locals
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-13 04:22:47 -08:00
|
|
|
pub struct MaybeStorageLive<'a> {
|
2025-01-07 15:19:05 +00:00
|
|
|
always_live_locals: Cow<'a, DenseBitSet<Local>>,
|
2020-03-29 14:16:29 -07:00
|
|
|
}
|
|
|
|
|
|
2022-12-13 04:22:47 -08:00
|
|
|
impl<'a> MaybeStorageLive<'a> {
|
2025-01-07 15:19:05 +00:00
|
|
|
pub fn new(always_live_locals: Cow<'a, DenseBitSet<Local>>) -> Self {
|
2020-03-29 14:16:29 -07:00
|
|
|
MaybeStorageLive { always_live_locals }
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-09-10 22:34:56 +02:00
|
|
|
|
2024-10-10 11:46:29 +11:00
|
|
|
impl<'a, 'tcx> Analysis<'tcx> for MaybeStorageLive<'a> {
|
2025-01-07 15:19:05 +00:00
|
|
|
type Domain = DenseBitSet<Local>;
|
2017-09-10 22:34:56 +02:00
|
|
|
|
2020-02-18 10:03:00 -08:00
|
|
|
const NAME: &'static str = "maybe_storage_live";
|
2017-09-10 22:34:56 +02:00
|
|
|
|
2023-05-06 14:13:12 +00:00
|
|
|
fn bottom_value(&self, body: &Body<'tcx>) -> Self::Domain {
|
2020-08-28 13:26:25 -07:00
|
|
|
// bottom = dead
|
2025-01-07 15:19:05 +00:00
|
|
|
DenseBitSet::new_empty(body.local_decls.len())
|
2017-09-10 22:34:56 +02:00
|
|
|
}
|
|
|
|
|
|
2024-11-26 14:30:49 +11:00
|
|
|
fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) {
|
|
|
|
|
state.union(&*self.always_live_locals);
|
2020-03-29 14:16:29 -07:00
|
|
|
|
|
|
|
|
for arg in body.args_iter() {
|
2024-11-26 14:30:49 +11:00
|
|
|
state.insert(arg);
|
2020-01-25 20:03:10 +01:00
|
|
|
}
|
2017-09-10 22:34:56 +02:00
|
|
|
}
|
|
|
|
|
|
2024-11-26 15:31:02 +11:00
|
|
|
fn apply_primary_statement_effect(
|
2024-10-10 09:49:33 +11:00
|
|
|
&mut self,
|
2024-11-26 14:30:49 +11:00
|
|
|
state: &mut Self::Domain,
|
2024-10-10 09:49:33 +11:00
|
|
|
stmt: &Statement<'tcx>,
|
|
|
|
|
_: Location,
|
|
|
|
|
) {
|
2017-09-10 22:34:56 +02:00
|
|
|
match stmt.kind {
|
2024-11-26 14:30:49 +11:00
|
|
|
StatementKind::StorageLive(l) => state.gen_(l),
|
|
|
|
|
StatementKind::StorageDead(l) => state.kill(l),
|
2017-09-10 22:34:56 +02:00
|
|
|
_ => (),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-16 00:00:00 +00:00
|
|
|
pub struct MaybeStorageDead<'a> {
|
2025-01-07 15:19:05 +00:00
|
|
|
always_live_locals: Cow<'a, DenseBitSet<Local>>,
|
2022-12-04 18:26:09 +00:00
|
|
|
}
|
|
|
|
|
|
2023-12-16 00:00:00 +00:00
|
|
|
impl<'a> MaybeStorageDead<'a> {
|
2025-01-07 15:19:05 +00:00
|
|
|
pub fn new(always_live_locals: Cow<'a, DenseBitSet<Local>>) -> Self {
|
2022-12-04 18:26:09 +00:00
|
|
|
MaybeStorageDead { always_live_locals }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-10 11:46:29 +11:00
|
|
|
impl<'a, 'tcx> Analysis<'tcx> for MaybeStorageDead<'a> {
|
2025-01-07 15:19:05 +00:00
|
|
|
type Domain = DenseBitSet<Local>;
|
2022-12-04 18:26:09 +00:00
|
|
|
|
|
|
|
|
const NAME: &'static str = "maybe_storage_dead";
|
|
|
|
|
|
2023-05-06 14:13:12 +00:00
|
|
|
fn bottom_value(&self, body: &Body<'tcx>) -> Self::Domain {
|
2022-12-04 18:26:09 +00:00
|
|
|
// bottom = live
|
2025-01-07 15:19:05 +00:00
|
|
|
DenseBitSet::new_empty(body.local_decls.len())
|
2022-12-04 18:26:09 +00:00
|
|
|
}
|
|
|
|
|
|
2024-11-26 14:30:49 +11:00
|
|
|
fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) {
|
2022-12-04 18:26:09 +00:00
|
|
|
assert_eq!(body.local_decls.len(), self.always_live_locals.domain_size());
|
2023-04-26 18:40:10 +00:00
|
|
|
// Do not iterate on return place and args, as they are trivially always live.
|
2022-12-04 18:26:09 +00:00
|
|
|
for local in body.vars_and_temps_iter() {
|
|
|
|
|
if !self.always_live_locals.contains(local) {
|
2024-11-26 14:30:49 +11:00
|
|
|
state.insert(local);
|
2022-12-04 18:26:09 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-26 15:31:02 +11:00
|
|
|
fn apply_primary_statement_effect(
|
2024-10-10 09:49:33 +11:00
|
|
|
&mut self,
|
2024-11-26 14:30:49 +11:00
|
|
|
state: &mut Self::Domain,
|
2024-10-10 09:49:33 +11:00
|
|
|
stmt: &Statement<'tcx>,
|
|
|
|
|
_: Location,
|
|
|
|
|
) {
|
2022-12-04 18:26:09 +00:00
|
|
|
match stmt.kind {
|
2024-11-26 14:30:49 +11:00
|
|
|
StatementKind::StorageLive(l) => state.kill(l),
|
|
|
|
|
StatementKind::StorageDead(l) => state.gen_(l),
|
2022-12-04 18:26:09 +00:00
|
|
|
_ => (),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-24 11:14:00 +11:00
|
|
|
type BorrowedLocalsResults<'mir, 'tcx> = ResultsCursor<'mir, 'tcx, MaybeBorrowedLocals>;
|
2020-06-08 14:50:39 -07:00
|
|
|
|
|
|
|
|
/// Dataflow analysis that determines whether each local requires storage at a
|
|
|
|
|
/// given location; i.e. whether its storage can go away without being observed.
|
2023-11-24 11:14:00 +11:00
|
|
|
pub struct MaybeRequiresStorage<'mir, 'tcx> {
|
|
|
|
|
borrowed_locals: BorrowedLocalsResults<'mir, 'tcx>,
|
2020-06-08 14:50:39 -07:00
|
|
|
}
|
|
|
|
|
|
2023-11-24 11:14:00 +11:00
|
|
|
impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> {
|
|
|
|
|
pub fn new(borrowed_locals: BorrowedLocalsResults<'mir, 'tcx>) -> Self {
|
2023-02-20 17:28:03 -05:00
|
|
|
MaybeRequiresStorage { borrowed_locals }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-10 11:46:29 +11:00
|
|
|
impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
|
2025-01-07 15:19:05 +00:00
|
|
|
type Domain = DenseBitSet<Local>;
|
2020-06-08 14:50:39 -07:00
|
|
|
|
|
|
|
|
const NAME: &'static str = "requires_storage";
|
|
|
|
|
|
2023-05-06 14:13:12 +00:00
|
|
|
fn bottom_value(&self, body: &Body<'tcx>) -> Self::Domain {
|
2020-08-28 13:26:25 -07:00
|
|
|
// bottom = dead
|
2025-01-07 15:19:05 +00:00
|
|
|
DenseBitSet::new_empty(body.local_decls.len())
|
2020-06-08 14:50:39 -07:00
|
|
|
}
|
|
|
|
|
|
2024-11-26 14:30:49 +11:00
|
|
|
fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) {
|
2020-06-08 14:50:39 -07:00
|
|
|
// The resume argument is live on function entry (we don't care about
|
|
|
|
|
// the `self` argument)
|
|
|
|
|
for arg in body.args_iter().skip(1) {
|
2024-11-26 14:30:49 +11:00
|
|
|
state.insert(arg);
|
2020-06-08 14:50:39 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-26 15:31:02 +11:00
|
|
|
fn apply_early_statement_effect(
|
2023-02-20 17:28:03 -05:00
|
|
|
&mut self,
|
2024-11-26 14:30:49 +11:00
|
|
|
state: &mut Self::Domain,
|
2023-05-06 14:13:12 +00:00
|
|
|
stmt: &Statement<'tcx>,
|
2020-06-08 14:50:39 -07:00
|
|
|
loc: Location,
|
|
|
|
|
) {
|
|
|
|
|
// If a place is borrowed in a statement, it needs storage for that statement.
|
2024-11-26 14:30:49 +11:00
|
|
|
MaybeBorrowedLocals::transfer_function(state).visit_statement(stmt, loc);
|
2020-06-08 14:50:39 -07:00
|
|
|
|
|
|
|
|
match &stmt.kind {
|
2024-11-26 14:30:49 +11:00
|
|
|
StatementKind::StorageDead(l) => state.kill(*l),
|
2020-06-08 14:50:39 -07:00
|
|
|
|
|
|
|
|
// If a place is assigned to in a statement, it needs storage for that statement.
|
|
|
|
|
StatementKind::Assign(box (place, _))
|
2022-04-05 17:14:59 -04:00
|
|
|
| StatementKind::SetDiscriminant { box place, .. }
|
|
|
|
|
| StatementKind::Deinit(box place) => {
|
2024-11-26 14:30:49 +11:00
|
|
|
state.gen_(place.local);
|
2020-06-08 14:50:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Nothing to do for these. Match exhaustively so this fails to compile when new
|
|
|
|
|
// variants are added.
|
|
|
|
|
StatementKind::AscribeUserType(..)
|
2022-09-06 18:41:01 +02:00
|
|
|
| StatementKind::PlaceMention(..)
|
2020-08-15 04:42:13 -07:00
|
|
|
| StatementKind::Coverage(..)
|
2020-06-08 14:50:39 -07:00
|
|
|
| StatementKind::FakeRead(..)
|
2022-12-20 00:51:17 +00:00
|
|
|
| StatementKind::ConstEvalCounter
|
2020-06-08 14:50:39 -07:00
|
|
|
| StatementKind::Nop
|
|
|
|
|
| StatementKind::Retag(..)
|
2022-07-12 10:05:00 +00:00
|
|
|
| StatementKind::Intrinsic(..)
|
2024-09-02 01:13:07 +08:00
|
|
|
| StatementKind::BackwardIncompatibleDropHint { .. }
|
2020-06-08 14:50:39 -07:00
|
|
|
| StatementKind::StorageLive(..) => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-26 15:31:02 +11:00
|
|
|
fn apply_primary_statement_effect(
|
2024-10-10 09:49:33 +11:00
|
|
|
&mut self,
|
2024-11-26 14:30:49 +11:00
|
|
|
state: &mut Self::Domain,
|
2024-10-10 09:49:33 +11:00
|
|
|
_: &Statement<'tcx>,
|
|
|
|
|
loc: Location,
|
|
|
|
|
) {
|
2022-07-06 13:26:26 -05:00
|
|
|
// If we move from a place then it only stops needing storage *after*
|
2020-06-08 14:50:39 -07:00
|
|
|
// that statement.
|
2024-11-26 14:30:49 +11:00
|
|
|
self.check_for_move(state, loc);
|
2020-06-08 14:50:39 -07:00
|
|
|
}
|
|
|
|
|
|
2024-11-26 15:31:02 +11:00
|
|
|
fn apply_early_terminator_effect(
|
2023-02-20 17:28:03 -05:00
|
|
|
&mut self,
|
2024-11-26 14:30:49 +11:00
|
|
|
state: &mut Self::Domain,
|
2023-05-06 14:13:12 +00:00
|
|
|
terminator: &Terminator<'tcx>,
|
2020-06-08 14:50:39 -07:00
|
|
|
loc: Location,
|
|
|
|
|
) {
|
|
|
|
|
// If a place is borrowed in a terminator, it needs storage for that terminator.
|
2024-11-26 14:30:49 +11:00
|
|
|
MaybeBorrowedLocals::transfer_function(state).visit_terminator(terminator, loc);
|
2020-06-08 14:50:39 -07:00
|
|
|
|
|
|
|
|
match &terminator.kind {
|
2022-04-16 09:27:54 -04:00
|
|
|
TerminatorKind::Call { destination, .. } => {
|
2024-11-26 14:30:49 +11:00
|
|
|
state.gen_(destination.local);
|
2020-06-08 14:50:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Note that we do *not* gen the `resume_arg` of `Yield` terminators. The reason for
|
|
|
|
|
// that is that a `yield` will return from the function, and `resume_arg` is written
|
2023-10-19 21:46:28 +00:00
|
|
|
// only when the coroutine is later resumed. Unlike `Call`, this doesn't require the
|
2020-06-08 14:50:39 -07:00
|
|
|
// place to have storage *before* the yield, only after.
|
|
|
|
|
TerminatorKind::Yield { .. } => {}
|
|
|
|
|
|
|
|
|
|
TerminatorKind::InlineAsm { operands, .. } => {
|
|
|
|
|
for op in operands {
|
|
|
|
|
match op {
|
|
|
|
|
InlineAsmOperand::Out { place, .. }
|
|
|
|
|
| InlineAsmOperand::InOut { out_place: place, .. } => {
|
|
|
|
|
if let Some(place) = place {
|
2024-11-26 14:30:49 +11:00
|
|
|
state.gen_(place.local);
|
2020-06-08 14:50:39 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
InlineAsmOperand::In { .. }
|
|
|
|
|
| InlineAsmOperand::Const { .. }
|
|
|
|
|
| InlineAsmOperand::SymFn { .. }
|
2023-12-26 16:07:35 +00:00
|
|
|
| InlineAsmOperand::SymStatic { .. }
|
|
|
|
|
| InlineAsmOperand::Label { .. } => {}
|
2020-06-08 14:50:39 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Nothing to do for these. Match exhaustively so this fails to compile when new
|
|
|
|
|
// variants are added.
|
2023-08-21 09:57:10 +02:00
|
|
|
TerminatorKind::UnwindTerminate(_)
|
2020-06-08 14:50:39 -07:00
|
|
|
| TerminatorKind::Assert { .. }
|
|
|
|
|
| TerminatorKind::Drop { .. }
|
|
|
|
|
| TerminatorKind::FalseEdge { .. }
|
|
|
|
|
| TerminatorKind::FalseUnwind { .. }
|
2023-10-19 16:06:43 +00:00
|
|
|
| TerminatorKind::CoroutineDrop
|
2020-06-08 14:50:39 -07:00
|
|
|
| TerminatorKind::Goto { .. }
|
2023-08-19 13:10:25 +02:00
|
|
|
| TerminatorKind::UnwindResume
|
2020-06-08 14:50:39 -07:00
|
|
|
| TerminatorKind::Return
|
2024-02-15 19:54:37 +00:00
|
|
|
| TerminatorKind::TailCall { .. }
|
2020-06-08 14:50:39 -07:00
|
|
|
| TerminatorKind::SwitchInt { .. }
|
|
|
|
|
| TerminatorKind::Unreachable => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-26 15:31:02 +11:00
|
|
|
fn apply_primary_terminator_effect<'t>(
|
2023-02-20 17:28:03 -05:00
|
|
|
&mut self,
|
2024-11-26 14:30:49 +11:00
|
|
|
state: &mut Self::Domain,
|
2023-05-07 10:20:43 +00:00
|
|
|
terminator: &'t Terminator<'tcx>,
|
2020-06-08 14:50:39 -07:00
|
|
|
loc: Location,
|
2023-05-27 16:27:04 +00:00
|
|
|
) -> TerminatorEdges<'t, 'tcx> {
|
2021-08-30 01:23:33 +01:00
|
|
|
match terminator.kind {
|
2020-06-08 14:50:39 -07:00
|
|
|
// For call terminators the destination requires storage for the call
|
|
|
|
|
// and after the call returns successfully, but not after a panic.
|
|
|
|
|
// Since `propagate_call_unwind` doesn't exist, we have to kill the
|
|
|
|
|
// destination here, and then gen it again in `call_return_effect`.
|
2022-04-16 09:27:54 -04:00
|
|
|
TerminatorKind::Call { destination, .. } => {
|
2024-11-26 14:30:49 +11:00
|
|
|
state.kill(destination.local);
|
2020-06-08 14:50:39 -07:00
|
|
|
}
|
|
|
|
|
|
2021-08-30 01:23:33 +01:00
|
|
|
// The same applies to InlineAsm outputs.
|
|
|
|
|
TerminatorKind::InlineAsm { ref operands, .. } => {
|
2024-11-26 14:30:49 +11:00
|
|
|
CallReturnPlaces::InlineAsm(operands).for_each(|place| state.kill(place.local));
|
2021-08-30 01:23:33 +01:00
|
|
|
}
|
|
|
|
|
|
2020-06-08 14:50:39 -07:00
|
|
|
// Nothing to do for these. Match exhaustively so this fails to compile when new
|
|
|
|
|
// variants are added.
|
2022-04-16 09:27:54 -04:00
|
|
|
TerminatorKind::Yield { .. }
|
2023-08-21 09:57:10 +02:00
|
|
|
| TerminatorKind::UnwindTerminate(_)
|
2020-06-08 14:50:39 -07:00
|
|
|
| TerminatorKind::Assert { .. }
|
|
|
|
|
| TerminatorKind::Drop { .. }
|
|
|
|
|
| TerminatorKind::FalseEdge { .. }
|
|
|
|
|
| TerminatorKind::FalseUnwind { .. }
|
2023-10-19 16:06:43 +00:00
|
|
|
| TerminatorKind::CoroutineDrop
|
2020-06-08 14:50:39 -07:00
|
|
|
| TerminatorKind::Goto { .. }
|
2023-08-19 13:10:25 +02:00
|
|
|
| TerminatorKind::UnwindResume
|
2020-06-08 14:50:39 -07:00
|
|
|
| TerminatorKind::Return
|
2024-02-15 19:54:37 +00:00
|
|
|
| TerminatorKind::TailCall { .. }
|
2020-06-08 14:50:39 -07:00
|
|
|
| TerminatorKind::SwitchInt { .. }
|
|
|
|
|
| TerminatorKind::Unreachable => {}
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-26 14:30:49 +11:00
|
|
|
self.check_for_move(state, loc);
|
2023-05-07 10:20:43 +00:00
|
|
|
terminator.edges()
|
2020-06-08 14:50:39 -07:00
|
|
|
}
|
|
|
|
|
|
2024-10-10 09:49:33 +11:00
|
|
|
fn apply_call_return_effect(
|
2023-02-20 17:28:03 -05:00
|
|
|
&mut self,
|
2024-11-26 14:30:49 +11:00
|
|
|
state: &mut Self::Domain,
|
2020-06-08 14:50:39 -07:00
|
|
|
_block: BasicBlock,
|
2021-08-30 01:23:33 +01:00
|
|
|
return_places: CallReturnPlaces<'_, 'tcx>,
|
2020-06-08 14:50:39 -07:00
|
|
|
) {
|
2024-11-26 14:30:49 +11:00
|
|
|
return_places.for_each(|place| state.gen_(place.local));
|
2020-06-08 14:50:39 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-24 11:14:00 +11:00
|
|
|
impl<'tcx> MaybeRequiresStorage<'_, 'tcx> {
|
2020-06-08 14:50:39 -07:00
|
|
|
/// Kill locals that are fully moved and have not been borrowed.
|
2024-11-26 14:30:49 +11:00
|
|
|
fn check_for_move(&mut self, state: &mut <Self as Analysis<'tcx>>::Domain, loc: Location) {
|
2023-02-20 17:28:03 -05:00
|
|
|
let body = self.borrowed_locals.body();
|
2024-11-26 14:30:49 +11:00
|
|
|
let mut visitor = MoveVisitor { state, borrowed_locals: &mut self.borrowed_locals };
|
2023-02-20 17:28:03 -05:00
|
|
|
visitor.visit_location(body, loc);
|
2020-06-08 14:50:39 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-10 10:14:58 +11:00
|
|
|
struct MoveVisitor<'a, 'mir, 'tcx> {
|
2023-11-24 11:14:00 +11:00
|
|
|
borrowed_locals: &'a mut BorrowedLocalsResults<'mir, 'tcx>,
|
2025-01-07 15:19:05 +00:00
|
|
|
state: &'a mut DenseBitSet<Local>,
|
2020-06-08 14:50:39 -07:00
|
|
|
}
|
|
|
|
|
|
2024-10-10 10:14:58 +11:00
|
|
|
impl<'tcx> Visitor<'tcx> for MoveVisitor<'_, '_, 'tcx> {
|
2022-07-01 16:21:21 +02:00
|
|
|
fn visit_local(&mut self, local: Local, context: PlaceContext, loc: Location) {
|
2020-06-08 14:50:39 -07:00
|
|
|
if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context {
|
2023-02-20 17:28:03 -05:00
|
|
|
self.borrowed_locals.seek_before_primary_effect(loc);
|
2024-10-10 11:21:16 +11:00
|
|
|
if !self.borrowed_locals.get().contains(local) {
|
2024-11-26 14:30:49 +11:00
|
|
|
self.state.kill(local);
|
2020-06-08 14:50:39 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|