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 {
35 target: target.clone(),
36 };
37 return;
38 }
39
40 let drop_arg =
42 self.raw_borrow_to_new_var(place.clone(), RefKind::Mut, Some("drop_arg".into()));
43
44 let trait_id = tref.trait_decl_ref.skip_binder.id;
46 let Some(tdecl) = self.ctx.translated.trait_decls.get(trait_id) else {
47 return;
48 };
49 let method_name = TraitItemName("drop_in_place".into());
50 let Some(bound_method) = tdecl.methods.iter().find(|m| m.name() == method_name) else {
51 return;
53 };
54 let method_decl_id = bound_method.skip_binder.item.id;
55
56 let drop_ret = self.fresh_var(Some("drop_ret".into()), Ty::mk_unit());
57 let fn_ptr = FnPtr::new(
58 FnPtrKind::Trait(tref.clone(), method_name, method_decl_id),
59 GenericArgs::empty(),
60 );
61 let call = Call {
62 func: FnOperand::Regular(fn_ptr),
63 args: Vec::from([Operand::Move(drop_arg)]),
64 dest: drop_ret,
65 };
66 term.kind = TerminatorKind::Call {
67 call,
68 target: target.clone(),
69 on_unwind: on_unwind.clone(),
70 };
71 }
72 }
73}
74
75pub struct Transform;
76
77impl UllbcPass for Transform {
78 fn transform_function(&self, ctx: &mut TransformCtx, decl: &mut FunDecl) {
79 if !ctx.options.desugar_drops {
80 return;
81 }
82 decl.transform_ullbc_terminators(ctx, |ctx, term| {
83 ctx.transform_drop_to_call(term);
84 });
85 }
86}