charon_lib/transform/inline_local_panic_functions.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
//! `panic!()` expands to:
//! ```ignore
//! fn panic_cold_explicit() -> ! {
//! core::panicking::panic_explicit()
//! }
//! panic_cold_explicit()
//! ```
//! Which defines a new function each time. This pass recognizes these functions and replaces calls
//! to them by a `Panic` terminator.
use derive_visitor::{visitor_enter_fn_mut, DriveMut};
use std::collections::HashSet;
use super::{ctx::LlbcPass, TransformCtx};
use crate::{
builtins,
llbc_ast::{
AbortKind, Call, FnOperand, FnPtr, FunId, FunIdOrTraitMethodRef, RawStatement, Statement,
},
names::Name,
};
pub struct Transform;
impl LlbcPass for Transform {
fn transform_ctx(&self, ctx: &mut TransformCtx<'_>) {
// Collect the functions that were generated by the `panic!` macro.
let mut panic_fns = HashSet::new();
ctx.for_each_fun_decl(|_ctx, decl, body| {
if let Ok(body) = body {
let body = body.as_structured().unwrap();
// If the whole body is only a call to this specific panic function.
if let [st] = body.body.statements.as_slice()
&& let RawStatement::Abort(AbortKind::Panic(name)) = &st.content
{
if name.equals_ref_name(builtins::EXPLICIT_PANIC_NAME) {
// FIXME: also check that the name of the function is
// `panic_cold_explicit`?
panic_fns.insert(decl.def_id);
}
}
}
});
let panic_name = Name::from_path(builtins::EXPLICIT_PANIC_NAME);
let panic_statement = RawStatement::Abort(AbortKind::Panic(panic_name));
// Replace each call to one such function with a `Panic`.
ctx.for_each_structured_body(|_ctx, body| {
body.body.drive_mut(&mut visitor_enter_fn_mut(
|st: &mut Statement| match &mut st.content {
RawStatement::Call(Call {
func:
FnOperand::Regular(FnPtr {
func: FunIdOrTraitMethodRef::Fun(FunId::Regular(fun_id)),
..
}),
..
}) if panic_fns.contains(fun_id) => {
st.content = panic_statement.clone();
}
_ => {}
},
));
});
// Remove these functions from the context.
for id in &panic_fns {
ctx.translated.fun_decls.remove(*id);
}
}
}