Skip to main content

rapx/analysis/points_to/
builder.rs

1use rustc_hir::def_id::DefId;
2use rustc_middle::ty::{self, Ty, TyCtxt, TypingEnv};
3
4use crate::analysis::alias::default::types::{is_not_drop, kind};
5
6use super::graph::PtsGraph;
7use super::slot::Slot;
8
9const MAX_FIELD_DEPTH: usize = 5;
10const MAX_DEREF_DEPTH: usize = 3;
11
12/// Build a PtsGraph from a MIR body, pre-registering all locals and their
13/// type-determined field slots up to depth limits.
14pub fn from_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> PtsGraph {
15    let body = tcx.optimized_mir(def_id);
16    let mut graph = PtsGraph::new();
17    let ty_env = TypingEnv::post_analysis(tcx, def_id);
18
19    for (local, local_decl) in body.local_decls.iter_enumerated() {
20        let ty = local_decl.ty;
21        let need_drop = ty.needs_drop(tcx, ty_env);
22        let may_drop = !is_not_drop(tcx, ty);
23
24        let slot = Slot::new(local.as_usize());
25        let slot_idx = graph.ensure_slot(slot.clone(), may_drop, need_drop);
26        graph.set_slot_kind(slot_idx, kind(ty));
27
28        register_field_slots(tcx, ty, &slot, slot_idx, &mut graph, 0, 0, ty_env);
29    }
30
31    graph
32}
33
34// ── Field slot registration ────────────────────────────────────────
35
36fn register_field_slots<'tcx>(
37    tcx: TyCtxt<'tcx>,
38    ty: Ty<'tcx>,
39    base_slot: &Slot,
40    _base_idx: usize,
41    graph: &mut PtsGraph,
42    field_depth: usize,
43    deref_depth: usize,
44    ty_env: TypingEnv<'tcx>,
45) {
46    if field_depth >= MAX_FIELD_DEPTH || deref_depth >= MAX_DEREF_DEPTH {
47        return;
48    }
49
50    match ty.kind() {
51        ty::Ref(_, inner_ty, _) | ty::RawPtr(inner_ty, _) => {
52            register_field_slots(
53                tcx, *inner_ty, base_slot, _base_idx, graph,
54                field_depth, deref_depth + 1, ty_env,
55            );
56        }
57        ty::Adt(adt_def, substs) => {
58            for (field_idx, field) in adt_def.all_fields().enumerate() {
59                let field_slot = base_slot.project(field_idx);
60                #[cfg(not(rapx_ge_99))]
61                let field_ty = field.ty(tcx, substs);
62                #[cfg(rapx_ge_99)]
63                let field_ty = field.ty(tcx, substs).skip_norm_wip();
64                let need_drop = field_ty.needs_drop(tcx, ty_env);
65                let may_drop = if deref_depth > 0 {
66                    true
67                } else {
68                    !is_not_drop(tcx, field_ty)
69                };
70                let field_idx_global =
71                    graph.ensure_slot(field_slot.clone(), may_drop, need_drop);
72                graph.set_slot_kind(field_idx_global, kind(field_ty));
73                register_field_slots(
74                    tcx, field_ty, &field_slot, field_idx_global, graph,
75                    field_depth + 1, deref_depth, ty_env,
76                );
77            }
78        }
79        ty::Tuple(fields) => {
80            for (field_idx, field_ty) in fields.iter().enumerate() {
81                let field_slot = base_slot.project(field_idx);
82                let may_drop = if deref_depth > 0 {
83                    true
84                } else {
85                    !is_not_drop(tcx, field_ty)
86                };
87                let need_drop = field_ty.needs_drop(tcx, ty_env);
88                let field_idx_global =
89                    graph.ensure_slot(field_slot.clone(), may_drop, need_drop);
90                graph.set_slot_kind(field_idx_global, kind(field_ty));
91                register_field_slots(
92                    tcx, field_ty, &field_slot, field_idx_global, graph,
93                    field_depth + 1, deref_depth, ty_env,
94                );
95            }
96        }
97        _ => {}
98    }
99}