2 use rustc_index
::vec
::IndexVec
;
3 use rustc_middle
::mir
::patch
::MirPatch
;
4 use rustc_middle
::mir
::visit
::NonUseContext
::VarDebugInfo
;
5 use rustc_middle
::mir
::visit
::{MutVisitor, PlaceContext}
;
6 use rustc_middle
::mir
::*;
7 use rustc_middle
::ty
::TyCtxt
;
11 pub struct DerefChecker
<'tcx
> {
13 patcher
: MirPatch
<'tcx
>,
14 local_decls
: IndexVec
<Local
, LocalDecl
<'tcx
>>,
17 impl<'tcx
> MutVisitor
<'tcx
> for DerefChecker
<'tcx
> {
18 fn tcx(&self) -> TyCtxt
<'tcx
> {
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
)
27 let mut place_local
= place
.local
;
29 let mut last_deref_idx
= 0;
31 let mut prev_temp
: Option
<Local
> = None
;
33 for (idx
, elem
) in place
.projection
[0..].iter().enumerate() {
34 if *elem
== ProjectionElem
::Deref
{
38 for (idx
, (p_ref
, p_elem
)) in place
.iter_projections().enumerate() {
39 if !p_ref
.projection
.is_empty() && p_elem
== ProjectionElem
::Deref
{
40 let ty
= p_ref
.ty(&self.local_decls
, self.tcx
).ty
;
41 let temp
= self.patcher
.new_local_with_info(
43 self.local_decls
[p_ref
.local
].source_info
.span
,
44 Some(Box
::new(LocalInfo
::DerefTemp
)),
47 self.patcher
.add_statement(loc
, StatementKind
::StorageLive(temp
));
49 // We are adding current p_ref's projections to our
50 // temp value, excluding projections we already covered.
51 let deref_place
= Place
::from(place_local
)
52 .project_deeper(&p_ref
.projection
[last_len
..], self.tcx
);
54 self.patcher
.add_assign(
57 Rvalue
::Use(Operand
::Move(deref_place
)),
60 last_len
= p_ref
.projection
.len();
62 // Change `Place` only if we are actually at the Place's last deref
63 if idx
== last_deref_idx
{
65 Place
::from(temp
).project_deeper(&place
.projection
[idx
..], self.tcx
);
69 // We are destroying the previous temp since it's no longer used.
70 if let Some(prev_temp
) = prev_temp
{
71 self.patcher
.add_statement(loc
, StatementKind
::StorageDead(prev_temp
));
74 prev_temp
= Some(temp
);
78 // Since we won't be able to reach final temp, we destroy it outside the loop.
79 if let Some(prev_temp
) = prev_temp
{
81 Location { block: loc.block, statement_index: loc.statement_index + 1 }
;
82 self.patcher
.add_statement(last_loc
, StatementKind
::StorageDead(prev_temp
));
88 pub fn deref_finder
<'tcx
>(tcx
: TyCtxt
<'tcx
>, body
: &mut Body
<'tcx
>) {
89 let patch
= MirPatch
::new(body
);
90 let mut checker
= DerefChecker { tcx, patcher: patch, local_decls: body.local_decls.clone() }
;
92 for (bb
, data
) in body
.basic_blocks_mut().iter_enumerated_mut() {
93 checker
.visit_basic_block_data(bb
, data
);
96 checker
.patcher
.apply(body
);
99 impl<'tcx
> MirPass
<'tcx
> for Derefer
{
100 fn run_pass(&self, tcx
: TyCtxt
<'tcx
>, body
: &mut Body
<'tcx
>) {
101 deref_finder(tcx
, body
);
102 body
.phase
= MirPhase
::Derefered
;