charon_lib/transform/
insert_ptr_metadata.rs1use crate::formatter::IntoFormatter;
2use crate::pretty::FmtWithCtx;
3use crate::transform::TransformCtx;
4use crate::transform::ctx::BodyTransformCtx;
5use crate::transform::index_to_function_calls::compute_subslice_end_idx;
6use crate::{transform::ctx::UllbcPass, ullbc_ast::*};
7use derive_generic_visitor::*;
8
9#[derive(Visitor)]
10struct BodyVisitor<'a, 'b> {
11 locals: &'a mut Locals,
12 statements: Vec<Statement>,
14 span: Span,
15 ctx: &'b TransformCtx,
16 params: &'a GenericParams,
17}
18
19fn is_sized_type_var<T: BodyTransformCtxWithParams>(ctx: &mut T, ty: &Ty) -> bool {
20 match ty.kind() {
21 TyKind::TypeVar(..) => {
22 if ctx.get_ctx().options.hide_marker_traits {
23 return true;
25 }
26 let params = ctx.get_params();
27 for clause in ¶ms.trait_clauses {
28 let tref = clause.trait_.clone().erase();
29 if tref.generics.types[0] == *ty
31 && ctx
32 .get_ctx()
33 .translated
34 .trait_decls
35 .get(tref.id)
36 .and_then(|decl| decl.item_meta.lang_item.clone())
37 == Some("sized".into())
38 {
39 return true;
40 }
41 }
42 false
43 }
44 _ => false,
45 }
46}
47
48fn no_metadata<T: BodyTransformCtx>(ctx: &T) -> Operand {
51 let unit_meta = ctx.get_ctx().translated.unit_metadata.clone().unwrap();
52 Operand::Copy(Place::new_global(unit_meta, Ty::mk_unit()))
53}
54
55fn compute_place_metadata_inner<T: BodyTransformCtx>(
57 ctx: &mut T,
58 place: &Place,
59 metadata_ty: &Ty,
60) -> Option<Operand> {
61 let (subplace, proj) = place.as_projection()?;
62 match proj {
63 ProjectionElem::Deref => {
65 let metadata_place = subplace
66 .clone()
67 .project(ProjectionElem::PtrMetadata, metadata_ty.clone());
68 Some(Operand::Copy(metadata_place))
69 }
70 ProjectionElem::Field { .. } => compute_place_metadata_inner(ctx, subplace, metadata_ty),
71 ProjectionElem::Index { .. } => None,
73 ProjectionElem::PtrMetadata { .. } => None,
75 ProjectionElem::Subslice { from, to, from_end } => {
77 let to_idx = compute_subslice_end_idx(ctx, subplace, *to.clone(), *from_end);
78 let diff_place = ctx.fresh_var(None, Ty::mk_usize());
79 ctx.insert_assn_stmt(
80 diff_place.clone(),
81 Rvalue::BinaryOp(BinOp::Sub(OverflowMode::UB), to_idx, *from.clone()),
83 );
84 Some(Operand::Copy(diff_place))
85 }
86 }
87}
88
89pub fn compute_place_metadata<T: BodyTransformCtxWithParams>(
92 ctx: &mut T,
93 place: &Place,
94) -> Operand {
95 trace!(
96 "getting ptr metadata for place: {}",
97 place.with_ctx(&ctx.get_ctx().into_fmt())
98 );
99 let metadata_ty = place
100 .ty()
101 .get_ptr_metadata(&ctx.get_ctx().translated)
102 .into_type();
103 if metadata_ty.is_unit()
104 || matches!(metadata_ty.kind(), TyKind::PtrMetadata(ty) if is_sized_type_var(ctx, ty))
105 {
106 return no_metadata(ctx);
108 }
109 trace!(
110 "computed metadata type: {}",
111 metadata_ty.with_ctx(&ctx.get_ctx().into_fmt())
112 );
113 compute_place_metadata_inner(ctx, place, &metadata_ty).unwrap_or_else(|| no_metadata(ctx))
114}
115
116pub trait BodyTransformCtxWithParams: BodyTransformCtx {
117 fn get_params(&self) -> &GenericParams;
118}
119
120impl BodyTransformCtxWithParams for BodyVisitor<'_, '_> {
121 fn get_params(&self) -> &GenericParams {
122 self.params
123 }
124}
125
126impl BodyTransformCtx for BodyVisitor<'_, '_> {
127 fn get_locals_mut(&mut self) -> &mut Locals {
128 self.locals
129 }
130
131 fn insert_storage_live_stmt(&mut self, local: LocalId) {
132 self.statements
133 .push(Statement::new(self.span, StatementKind::StorageLive(local)));
134 }
135
136 fn insert_assn_stmt(&mut self, place: Place, rvalue: Rvalue) {
137 self.statements.push(Statement::new(
138 self.span,
139 StatementKind::Assign(place, rvalue),
140 ));
141 }
142
143 fn get_ctx(&self) -> &TransformCtx {
144 self.ctx
145 }
146
147 fn insert_storage_dead_stmt(&mut self, local: LocalId) {
148 self.statements
149 .push(Statement::new(self.span, StatementKind::StorageDead(local)));
150 }
151}
152
153impl VisitBodyMut for BodyVisitor<'_, '_> {
154 fn visit_rvalue(&mut self, x: &mut Rvalue) -> ::std::ops::ControlFlow<Self::Break> {
155 if let Rvalue::Ref {
156 place,
157 ptr_metadata,
158 ..
159 }
160 | Rvalue::RawPtr {
161 place,
162 ptr_metadata,
163 ..
164 } = x
165 {
166 *ptr_metadata = compute_place_metadata(self, place);
167 }
168 Continue(())
169 }
170}
171
172pub struct Transform;
173
174impl Transform {
175 fn transform_body_with_param(
176 &self,
177 ctx: &mut TransformCtx,
178 b: &mut ExprBody,
179 params: &GenericParams,
180 ) {
181 b.body.iter_mut().for_each(|data| {
182 data.transform(|st: &mut Statement| {
183 let mut visitor = BodyVisitor {
184 locals: &mut b.locals,
185 statements: Vec::new(),
186 span: st.span,
187 ctx: &ctx,
188 params,
189 };
190 let _ = st.drive_body_mut(&mut visitor);
191 visitor.statements
192 });
193 });
194 }
195}
196
197impl UllbcPass for Transform {
209 fn transform_function(&self, ctx: &mut TransformCtx, decl: &mut FunDecl) {
210 if let Ok(body) = &mut decl.body {
211 self.transform_body_with_param(
212 ctx,
213 body.as_unstructured_mut().unwrap(),
214 &decl.signature.generics,
215 )
216 }
217 }
218}