about summary refs log tree commit diff
path: root/compiler/rustc_mir_transform/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_mir_transform/src')
-rw-r--r--compiler/rustc_mir_transform/src/deref_separator.rs110
-rw-r--r--compiler/rustc_mir_transform/src/generator.rs4
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs3
3 files changed, 65 insertions, 52 deletions
diff --git a/compiler/rustc_mir_transform/src/deref_separator.rs b/compiler/rustc_mir_transform/src/deref_separator.rs
index 57a95a67df7..bfb3ad1be27 100644
--- a/compiler/rustc_mir_transform/src/deref_separator.rs
+++ b/compiler/rustc_mir_transform/src/deref_separator.rs
@@ -1,9 +1,11 @@
 use crate::MirPass;
 use rustc_index::vec::IndexVec;
 use rustc_middle::mir::patch::MirPatch;
+use rustc_middle::mir::visit::NonUseContext::VarDebugInfo;
 use rustc_middle::mir::visit::{MutVisitor, PlaceContext};
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
+
 pub struct Derefer;
 
 pub struct DerefChecker<'tcx> {
@@ -17,63 +19,68 @@ impl<'tcx> MutVisitor<'tcx> for DerefChecker<'tcx> {
         self.tcx
     }
 
-    fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, loc: Location) {
-        let mut place_local = place.local;
-        let mut last_len = 0;
-        let mut last_deref_idx = 0;
+    fn visit_place(&mut self, place: &mut Place<'tcx>, cntxt: PlaceContext, loc: Location) {
+        if !place.projection.is_empty()
+            && cntxt != PlaceContext::NonUse(VarDebugInfo)
+            && place.projection[1..].contains(&ProjectionElem::Deref)
+        {
+            let mut place_local = place.local;
+            let mut last_len = 0;
+            let mut last_deref_idx = 0;
 
-        let mut prev_temp: Option<Local> = None;
+            let mut prev_temp: Option<Local> = None;
 
-        for (idx, (p_ref, p_elem)) in place.iter_projections().enumerate() {
-            if p_elem == ProjectionElem::Deref && !p_ref.projection.is_empty() {
-                last_deref_idx = idx;
-            }
-        }
-
-        for (idx, (p_ref, p_elem)) in place.iter_projections().enumerate() {
-            if p_elem == ProjectionElem::Deref && !p_ref.projection.is_empty() {
-                let ty = p_ref.ty(&self.local_decls, self.tcx).ty;
-                let temp = self.patcher.new_local_with_info(
-                    ty,
-                    self.local_decls[p_ref.local].source_info.span,
-                    Some(Box::new(LocalInfo::DerefTemp)),
-                );
-
-                self.patcher.add_statement(loc, StatementKind::StorageLive(temp));
-
-                // We are adding current p_ref's projections to our
-                // temp value, excluding projections we already covered.
-                let deref_place = Place::from(place_local)
-                    .project_deeper(&p_ref.projection[last_len..], self.tcx);
-
-                self.patcher.add_assign(
-                    loc,
-                    Place::from(temp),
-                    Rvalue::Use(Operand::Move(deref_place)),
-                );
-                place_local = temp;
-                last_len = p_ref.projection.len();
-
-                // Change `Place` only if we are actually at the Place's last deref
-                if idx == last_deref_idx {
-                    let temp_place =
-                        Place::from(temp).project_deeper(&place.projection[idx..], self.tcx);
-                    *place = temp_place;
+            for (idx, elem) in place.projection[0..].iter().enumerate() {
+                if *elem == ProjectionElem::Deref {
+                    last_deref_idx = idx;
                 }
-
-                // We are destroying the previous temp since it's no longer used.
-                if let Some(prev_temp) = prev_temp {
-                    self.patcher.add_statement(loc, StatementKind::StorageDead(prev_temp));
+            }
+            for (idx, (p_ref, p_elem)) in place.iter_projections().enumerate() {
+                if !p_ref.projection.is_empty() && p_elem == ProjectionElem::Deref {
+                    let ty = p_ref.ty(&self.local_decls, self.tcx).ty;
+                    let temp = self.patcher.new_local_with_info(
+                        ty,
+                        self.local_decls[p_ref.local].source_info.span,
+                        Some(Box::new(LocalInfo::DerefTemp)),
+                    );
+
+                    self.patcher.add_statement(loc, StatementKind::StorageLive(temp));
+
+                    // We are adding current p_ref's projections to our
+                    // temp value, excluding projections we already covered.
+                    let deref_place = Place::from(place_local)
+                        .project_deeper(&p_ref.projection[last_len..], self.tcx);
+
+                    self.patcher.add_assign(
+                        loc,
+                        Place::from(temp),
+                        Rvalue::Use(Operand::Move(deref_place)),
+                    );
+                    place_local = temp;
+                    last_len = p_ref.projection.len();
+
+                    // Change `Place` only if we are actually at the Place's last deref
+                    if idx == last_deref_idx {
+                        let temp_place =
+                            Place::from(temp).project_deeper(&place.projection[idx..], self.tcx);
+                        *place = temp_place;
+                    }
+
+                    // We are destroying the previous temp since it's no longer used.
+                    if let Some(prev_temp) = prev_temp {
+                        self.patcher.add_statement(loc, StatementKind::StorageDead(prev_temp));
+                    }
+
+                    prev_temp = Some(temp);
                 }
-
-                prev_temp = Some(temp);
             }
-        }
 
-        // Since we won't be able to reach final temp, we destroy it outside the loop.
-        if let Some(prev_temp) = prev_temp {
-            let last_loc = Location { block: loc.block, statement_index: loc.statement_index + 1 };
-            self.patcher.add_statement(last_loc, StatementKind::StorageDead(prev_temp));
+            // Since we won't be able to reach final temp, we destroy it outside the loop.
+            if let Some(prev_temp) = prev_temp {
+                let last_loc =
+                    Location { block: loc.block, statement_index: loc.statement_index + 1 };
+                self.patcher.add_statement(last_loc, StatementKind::StorageDead(prev_temp));
+            }
         }
     }
 }
@@ -92,5 +99,6 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
 impl<'tcx> MirPass<'tcx> for Derefer {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         deref_finder(tcx, body);
+        body.phase = MirPhase::Derefered;
     }
 }
diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs
index 4a3505ca3ff..9eb77f60213 100644
--- a/compiler/rustc_mir_transform/src/generator.rs
+++ b/compiler/rustc_mir_transform/src/generator.rs
@@ -49,6 +49,7 @@
 //! For generators with state 1 (returned) and state 2 (poisoned) it does nothing.
 //! Otherwise it drops all the values in scope at the last suspension point.
 
+use crate::deref_separator::deref_finder;
 use crate::simplify;
 use crate::util::expand_aggregate;
 use crate::MirPass;
@@ -1368,6 +1369,9 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
 
         // Create the Generator::resume function
         create_generator_resume_function(tcx, transform, body, can_return);
+
+        // Run derefer to fix Derefs that are not in the first place
+        deref_finder(tcx, body);
     }
 }
 
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 66fb01bd464..9526c0acc66 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -1,5 +1,5 @@
 //! Inlining pass for MIR functions
-
+use crate::deref_separator::deref_finder;
 use rustc_attr::InlineAttr;
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::Idx;
@@ -53,6 +53,7 @@ impl<'tcx> MirPass<'tcx> for Inline {
             debug!("running simplify cfg on {:?}", body.source);
             CfgSimplifier::new(body).simplify();
             remove_dead_blocks(tcx, body);
+            deref_finder(tcx, body);
         }
     }
 }