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