use rustc_middle::mir::{BasicBlock, Place, Rvalue, Statement, Terminator};
use super::state::{VmState, VmValue};
pub(crate) mod rvalue;
pub(crate) mod statement;
pub(crate) mod terminator;
pub(crate) struct RvalueRule {
pub name: &'static str,
pub apply: for<'z3, 'tcx> fn(
&mut VmState<'z3, 'tcx>,
&Place<'tcx>,
&Rvalue<'tcx>,
) -> Option<VmValue<'z3, 'tcx>>,
}
pub(crate) struct TerminatorRule {
pub name: &'static str,
pub apply:
for<'z3, 'tcx> fn(&mut VmState<'z3, 'tcx>, &Terminator<'tcx>, Option<BasicBlock>) -> bool,
}
pub(crate) struct StatementRule {
pub name: &'static str,
pub apply: for<'z3, 'tcx> fn(&mut VmState<'z3, 'tcx>, &Statement<'tcx>) -> bool,
}
pub(crate) const RVALUE_RULES: &[RvalueRule] = &[
RvalueRule { name: "use", apply: rvalue::eval_use },
RvalueRule { name: "ref", apply: rvalue::eval_ref },
RvalueRule { name: "raw_ptr", apply: rvalue::eval_raw_ptr },
RvalueRule { name: "binary_op", apply: rvalue::eval_binary_op },
RvalueRule { name: "unary_op", apply: rvalue::eval_unary_op },
RvalueRule { name: "cast", apply: rvalue::eval_cast },
RvalueRule { name: "aggregate", apply: rvalue::eval_aggregate },
RvalueRule { name: "discriminant", apply: rvalue::eval_discriminant },
#[cfg(not(rapx_ge_99))]
RvalueRule { name: "shallow_init_box", apply: rvalue::eval_shallow_init_box },
RvalueRule { name: "copy_for_deref", apply: rvalue::eval_copy_for_deref },
RvalueRule { name: "repeat", apply: rvalue::eval_repeat },
RvalueRule { name: "thread_local_ref", apply: rvalue::eval_thread_local_ref },
#[cfg(not(rapx_ge_95))]
RvalueRule { name: "nullary_op", apply: rvalue::eval_nullary_op },
RvalueRule { name: "wrap_unsafe_binder", apply: rvalue::eval_wrap_unsafe_binder },
#[cfg(rapx_rvalue_has_reborrow)]
RvalueRule { name: "reborrow", apply: rvalue::eval_reborrow },
];
pub(crate) const TERMINATOR_RULES: &[TerminatorRule] = &[
TerminatorRule { name: "call", apply: terminator::exec_call },
TerminatorRule { name: "switch_int", apply: terminator::exec_switch_int },
TerminatorRule { name: "assert", apply: terminator::exec_assert },
TerminatorRule { name: "drop", apply: terminator::exec_drop },
TerminatorRule { name: "nop", apply: terminator::exec_nop },
];
pub(crate) const STATEMENT_RULES: &[StatementRule] = &[
StatementRule { name: "assign", apply: statement::exec_assign },
StatementRule { name: "storage_live", apply: statement::exec_storage_live },
StatementRule { name: "storage_dead", apply: statement::exec_storage_dead },
StatementRule { name: "nop", apply: statement::exec_nop },
];
pub(crate) fn eval_rvalue<'z3, 'tcx>(
state: &mut VmState<'z3, 'tcx>,
place: &Place<'tcx>,
rvalue: &Rvalue<'tcx>,
) -> VmValue<'z3, 'tcx> {
for rule in RVALUE_RULES {
if let Some(value) = (rule.apply)(state, place, rvalue) {
crate::rap_debug!("rvalue rule: {}", rule.name);
return value;
}
}
unreachable!("no rule for rvalue: {:?}", rvalue)
}
pub(crate) fn exec_terminator<'z3, 'tcx>(
state: &mut VmState<'z3, 'tcx>,
terminator: &Terminator<'tcx>,
switch_succ: Option<BasicBlock>,
) {
for rule in TERMINATOR_RULES {
if (rule.apply)(state, terminator, switch_succ) {
crate::rap_debug!("terminator rule: {}", rule.name);
return;
}
}
unreachable!("no rule for terminator: {:?}", terminator.kind)
}
pub(crate) fn exec_statement<'z3, 'tcx>(state: &mut VmState<'z3, 'tcx>, statement: &Statement<'tcx>) {
for rule in STATEMENT_RULES {
if (rule.apply)(state, statement) {
crate::rap_debug!("statement rule: {}", rule.name);
return;
}
}
unreachable!("no rule for statement: {:?}", statement.kind)
}