charon_lib/transform/normalize/
desugar_drops.rs1use super::super::ctx::UllbcPass;
2use crate::{
3 transform::{
4 TransformCtx,
5 ctx::{BodyTransformCtx, UllbcStatementTransformCtx},
6 },
7 ullbc_ast::*,
8};
9
10fn is_noop_destruct(tref: &TraitRef) -> bool {
11 matches!(
12 &tref.kind,
13 TraitRefKind::BuiltinOrAuto {
14 builtin_data: BuiltinImplData::NoopDestruct,
15 ..
16 }
17 )
18}
19
20impl<'a> UllbcStatementTransformCtx<'a> {
21 fn transform_drop_to_call(&mut self, term: &mut Terminator) {
24 if let TerminatorKind::Drop {
25 kind: DropKind::Precise,
26 place,
27 tref,
28 target,
29 on_unwind,
30 } = &mut term.kind
31 {
32 if is_noop_destruct(tref) {
34 term.kind = TerminatorKind::Goto { target: *target };
35 return;
36 }
37
38 let drop_arg =
40 self.raw_borrow_to_new_var(place.clone(), RefKind::Mut, Some("drop_arg".into()));
41
42 let trait_id = tref.trait_decl_ref.skip_binder.id;
44 let Some(tdecl) = self.ctx.translated.trait_decls.get(trait_id) else {
45 return;
46 };
47 let method_name = TraitItemName("drop_in_place".into());
48 let Some(bound_method) = tdecl.methods.iter().find(|m| m.name() == method_name) else {
49 return;
51 };
52 let method_decl_id = bound_method.skip_binder.item.id;
53
54 let drop_ret = self.fresh_var(Some("drop_ret".into()), Ty::mk_unit());
55 let fn_ptr = FnPtr::new(
56 FnPtrKind::Trait(tref.clone(), method_name, method_decl_id),
57 GenericArgs::empty(),
58 );
59 let call = Call {
60 func: FnOperand::Regular(fn_ptr),
61 args: Vec::from([Operand::Move(drop_arg)]),
62 dest: drop_ret,
63 };
64 term.kind = TerminatorKind::Call {
65 call,
66 target: *target,
67 on_unwind: *on_unwind,
68 };
69 }
70 }
71}
72
73pub struct Transform;
74
75impl UllbcPass for Transform {
76 fn should_run(&self, options: &crate::options::TranslateOptions) -> bool {
77 options.desugar_drops
78 }
79 fn transform_function(&self, ctx: &mut TransformCtx, decl: &mut FunDecl) {
80 decl.transform_ullbc_terminators(ctx, |ctx, term| {
81 ctx.transform_drop_to_call(term);
82 });
83 }
84}