charon_lib/transform/resugar/
reconstruct_panic_calls.rs1use std::collections::HashMap;
3
4use crate::ast::{Name, from_rustc, names};
5use crate::transform::{CowBox, TransformCtx, ctx::UllbcPass};
6use crate::ullbc_ast::*;
7
8pub struct Transform {
9 panic_fns: HashMap<FunDeclId, Name>,
10}
11
12impl Transform {
13 pub fn new(ctx: &TransformCtx) -> CowBox<dyn UllbcPass> {
14 let explicit_panic = Name::from_path(names::EXPLICIT_PANIC_NAME);
15 let assert_failed = Name::from_path(&["core", "panicking", "assert_failed"]);
16 let panic_fns = ctx
17 .translated
18 .fun_decls
19 .iter_indexed()
20 .filter_map(|(id, decl)| {
21 let is_panic_lang_item = matches!(
24 decl.item_meta.lang_item,
25 Some(
26 from_rustc::LangItem::Panic
27 | from_rustc::LangItem::PanicFmt
28 | from_rustc::LangItem::BeginPanic
29 )
30 );
31 (is_panic_lang_item
32 || decl.item_meta.name == explicit_panic
33 || decl.item_meta.name == assert_failed)
34 .then(|| (id, decl.item_meta.name.clone()))
35 })
36 .collect();
37 CowBox::Owned(Box::new(Self { panic_fns }))
38 }
39}
40
41impl UllbcPass for Transform {
42 fn should_run(&self, options: &crate::options::TranslateOptions) -> bool {
43 options.reconstruct_panic_calls
44 }
45
46 fn transform_body(&self, _ctx: &mut TransformCtx, body: &mut ExprBody) {
47 for block in &mut body.body {
48 if let TerminatorKind::Call {
49 call, on_unwind, ..
50 } = &block.terminator.kind
51 && let FnOperand::Regular(fn_ptr) = &call.func
52 && let FnPtrKind::Fun(id) = fn_ptr.kind.as_ref()
53 && let Some(name) = self.panic_fns.get(id)
54 {
55 block.terminator.kind = TerminatorKind::Panic {
56 name: name.clone(),
57 on_unwind: *on_unwind,
58 };
59 }
60 }
61 }
62}