]>
Commit | Line | Data |
---|---|---|
04454e1e | 1 | use crate::MirPass; |
49aad941 | 2 | use rustc_index::IndexVec; |
04454e1e | 3 | use rustc_middle::mir::patch::MirPatch; |
923072b8 | 4 | use rustc_middle::mir::visit::NonUseContext::VarDebugInfo; |
04454e1e FG |
5 | use rustc_middle::mir::visit::{MutVisitor, PlaceContext}; |
6 | use rustc_middle::mir::*; | |
7 | use rustc_middle::ty::TyCtxt; | |
923072b8 | 8 | |
04454e1e FG |
9 | pub struct Derefer; |
10 | ||
11 | pub struct DerefChecker<'tcx> { | |
12 | tcx: TyCtxt<'tcx>, | |
13 | patcher: MirPatch<'tcx>, | |
14 | local_decls: IndexVec<Local, LocalDecl<'tcx>>, | |
15 | } | |
16 | ||
17 | impl<'tcx> MutVisitor<'tcx> for DerefChecker<'tcx> { | |
18 | fn tcx(&self) -> TyCtxt<'tcx> { | |
19 | self.tcx | |
20 | } | |
21 | ||
923072b8 FG |
22 | fn visit_place(&mut self, place: &mut Place<'tcx>, cntxt: PlaceContext, loc: Location) { |
23 | if !place.projection.is_empty() | |
24 | && cntxt != PlaceContext::NonUse(VarDebugInfo) | |
25 | && place.projection[1..].contains(&ProjectionElem::Deref) | |
26 | { | |
27 | let mut place_local = place.local; | |
28 | let mut last_len = 0; | |
29 | let mut last_deref_idx = 0; | |
04454e1e | 30 | |
923072b8 FG |
31 | for (idx, elem) in place.projection[0..].iter().enumerate() { |
32 | if *elem == ProjectionElem::Deref { | |
33 | last_deref_idx = idx; | |
04454e1e | 34 | } |
923072b8 | 35 | } |
064997fb | 36 | |
923072b8 FG |
37 | for (idx, (p_ref, p_elem)) in place.iter_projections().enumerate() { |
38 | if !p_ref.projection.is_empty() && p_elem == ProjectionElem::Deref { | |
39 | let ty = p_ref.ty(&self.local_decls, self.tcx).ty; | |
f2b60f7d | 40 | let temp = self.patcher.new_internal_with_info( |
923072b8 FG |
41 | ty, |
42 | self.local_decls[p_ref.local].source_info.span, | |
353b0b11 | 43 | LocalInfo::DerefTemp, |
923072b8 FG |
44 | ); |
45 | ||
923072b8 FG |
46 | // We are adding current p_ref's projections to our |
47 | // temp value, excluding projections we already covered. | |
48 | let deref_place = Place::from(place_local) | |
49 | .project_deeper(&p_ref.projection[last_len..], self.tcx); | |
50 | ||
51 | self.patcher.add_assign( | |
52 | loc, | |
53 | Place::from(temp), | |
064997fb | 54 | Rvalue::CopyForDeref(deref_place), |
923072b8 FG |
55 | ); |
56 | place_local = temp; | |
57 | last_len = p_ref.projection.len(); | |
58 | ||
59 | // Change `Place` only if we are actually at the Place's last deref | |
60 | if idx == last_deref_idx { | |
61 | let temp_place = | |
62 | Place::from(temp).project_deeper(&place.projection[idx..], self.tcx); | |
63 | *place = temp_place; | |
64 | } | |
04454e1e | 65 | } |
04454e1e | 66 | } |
04454e1e FG |
67 | } |
68 | } | |
69 | } | |
70 | ||
71 | pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { | |
72 | let patch = MirPatch::new(body); | |
73 | let mut checker = DerefChecker { tcx, patcher: patch, local_decls: body.local_decls.clone() }; | |
74 | ||
f2b60f7d | 75 | for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() { |
04454e1e FG |
76 | checker.visit_basic_block_data(bb, data); |
77 | } | |
78 | ||
79 | checker.patcher.apply(body); | |
80 | } | |
81 | ||
82 | impl<'tcx> MirPass<'tcx> for Derefer { | |
83 | fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { | |
84 | deref_finder(tcx, body); | |
85 | } | |
86 | } |