Skip to main content

charon_lib/transform/normalize/
desugar_drops.rs

1use crate::{
2    transform::{
3        TransformCtx,
4        ctx::{BodyTransformCtx, UllbcPass, UllbcStatementTransformCtx},
5    },
6    ullbc_ast::*,
7};
8
9fn is_noop_destruct(glue: &FnPtr) -> bool {
10    match glue.kind.as_ref() {
11        FnPtrKind::Trait(tref, _) => matches!(
12            &tref.kind,
13            TraitRefKind::BuiltinOrAuto {
14                builtin_data: BuiltinImplData::NoopDestruct,
15                ..
16            }
17        ),
18        _ => false,
19    }
20}
21
22impl<'a> UllbcStatementTransformCtx<'a> {
23    /// Transform a Drop to a Call that calls the drop_glue method.
24    /// If we cannot desugar this drop, we just leave it unchanged.
25    fn transform_drop_to_call(&mut self, term: &mut Terminator) {
26        if let TerminatorKind::Drop {
27            kind: DropKind::Precise,
28            place,
29            fn_ptr,
30            target,
31            on_unwind,
32        } = &mut term.kind
33        {
34            // check if this drop is noop
35            if is_noop_destruct(fn_ptr) {
36                term.kind = TerminatorKind::Goto { target: *target };
37                return;
38            }
39
40            // assign `&mut place` to a new variable
41            let drop_arg =
42                self.borrow_to_new_var(place.clone(), BorrowKind::Mut, Some("drop_arg".into()));
43
44            let drop_ret = self.fresh_var(Some("drop_ret".into()), Ty::mk_unit());
45            let call = Call {
46                func: FnOperand::Regular(fn_ptr.clone()),
47                args: Vec::from([Operand::Move(drop_arg)]),
48                dest: drop_ret,
49                safety: CallSafety::Safe, // drop_glue is unsafe, but here we know it's safe
50            };
51            term.kind = TerminatorKind::Call {
52                call,
53                target: *target,
54                on_unwind: *on_unwind,
55            };
56        }
57    }
58}
59
60pub struct Transform;
61
62impl UllbcPass for Transform {
63    fn should_run(&self, options: &crate::options::TranslateOptions) -> bool {
64        options.desugar_drops
65    }
66    fn transform_function(&self, ctx: &mut TransformCtx, decl: &mut FunDecl) {
67        decl.transform_ullbc_terminators(ctx, |ctx, term| {
68            ctx.transform_drop_to_call(term);
69        });
70    }
71}