use rustc_hir::def_id::DefId;
use rustc_middle::mir::{BasicBlock, Body, Operand, Place, TerminatorKind};
use crate::analysis::dataflow::types::DataflowGraph;
use crate::compat::Spanned;
use crate::helpers::def_use::{RelevantPlaces, call_args_uses_at, terminator_use_def};
use crate::helpers::mir_utils;
use super::super::types::RelevantItem;
use super::super::visitor::BackwardSlicer;
use super::call;
impl<'tcx> BackwardSlicer<'tcx> {
#[allow(clippy::too_many_arguments)]
pub(super) fn visit_call_terminator(
&self,
def_id: DefId,
block: BasicBlock,
terminator: &rustc_middle::mir::Terminator<'tcx>,
func: &Operand<'tcx>,
args: &[Spanned<Operand<'tcx>>],
destination: &Place<'tcx>,
flow: &DataflowGraph,
body: &Body<'tcx>,
relevant: &mut RelevantPlaces,
items: &mut Vec<RelevantItem<'tcx>>,
keep_invalidations: bool,
keep_owner: bool,
) {
if keep_invalidations {
let is_drop_call = mir_utils::dep_callee_def_id(func).is_some_and(|c| {
crate::verify::api_classify::is_manually_drop_drop(Some(c))
|| crate::verify::api_classify::is_std_drop(Some(c))
});
if is_drop_call {
items.push(RelevantItem::Terminator {
def_id,
block,
switch_succ: None,
});
relevant.extend(call_args_uses_at(args, &[0]));
return;
}
}
if keep_owner {
let dest_ty = body.local_decls[destination.local].ty;
let typing_env = rustc_middle::ty::TypingEnv::non_body_analysis(self.tcx, def_id);
if dest_ty.needs_drop(self.tcx, typing_env) {
let use_def = terminator_use_def(terminator);
items.push(RelevantItem::Terminator {
def_id,
block,
switch_succ: None,
});
relevant.remove_all(&use_def.defs);
relevant.extend(use_def.uses);
return;
}
}
call::visit(
self.tcx,
def_id,
block,
func,
args,
destination,
flow,
body,
relevant,
items,
);
}
}
#[allow(clippy::too_many_arguments)]
pub(super) fn visit_non_call_terminator<'tcx>(
def_id: DefId,
block: BasicBlock,
terminator: &rustc_middle::mir::Terminator<'tcx>,
relevant: &mut RelevantPlaces,
items: &mut Vec<RelevantItem<'tcx>>,
keep_invalidations: bool,
successor: Option<BasicBlock>,
) {
if keep_invalidations && matches!(terminator.kind, TerminatorKind::Drop { .. }) {
items.push(RelevantItem::Terminator {
def_id,
block,
switch_succ: None,
});
return;
}
let use_def = terminator_use_def(terminator);
let path_successor = match terminator.kind {
TerminatorKind::SwitchInt { .. } => Some(successor),
TerminatorKind::Assert { .. } => Some(None),
_ => None,
};
if let Some(switch_succ) = path_successor {
items.push(RelevantItem::Terminator {
def_id,
block,
switch_succ,
});
relevant.extend(use_def.uses);
return;
}
if use_def.defs.intersects(relevant) {
items.push(RelevantItem::Terminator {
def_id,
block,
switch_succ: None,
});
relevant.remove_all(&use_def.defs);
relevant.extend(use_def.uses);
return;
}
if use_def.uses.intersects(relevant) {
items.push(RelevantItem::Terminator {
def_id,
block,
switch_succ: None,
});
}
}