Skip to main content

charon_lib/transform/resugar/
reconstruct_panic_calls.rs

1//! Transform calls to builtin panicking functions into `TerminatorKind::Panic`.
2use 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                // TODO: There are about 30 panic-related lang items. Decide which of the others
22                // should also be reconstructed.
23                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}