]> git.proxmox.com Git - rustc.git/blobdiff - src/librustc_mir/transform/add_retag.rs
New upstream version 1.40.0+dfsg1
[rustc.git] / src / librustc_mir / transform / add_retag.rs
index e66c11aa36e0e5d1fba1e51cfc7229d3566efbd5..b56a1b263fd6a62e08735f12bc9e90a975879675 100644 (file)
@@ -14,43 +14,30 @@ pub struct AddRetag;
 /// after the assignment, we can be sure to obtain the same place value.
 /// (Concurrent accesses by other threads are no problem as these are anyway non-atomic
 /// copies.  Data races are UB.)
-fn is_stable<'tcx>(
-    place: &Place<'tcx>,
+fn is_stable(
+    place: PlaceRef<'_, '_>,
 ) -> bool {
-    use rustc::mir::Place::*;
-
-    match *place {
-        // Locals and statics have stable addresses, for sure
-        Local { .. } |
-        Promoted { .. } |
-        Static { .. } =>
-            true,
-        // Recurse for projections
-        Projection(ref proj) => {
-            match proj.elem {
-                // Which place this evaluates to can change with any memory write,
-                // so cannot assume this to be stable.
-                ProjectionElem::Deref =>
-                    false,
-                // Array indices are intersting, but MIR building generates a *fresh*
-                // temporary for every array access, so the index cannot be changed as
-                // a side-effect.
-                ProjectionElem::Index { .. } |
-                // The rest is completely boring, they just offset by a constant.
-                ProjectionElem::Field { .. } |
-                ProjectionElem::ConstantIndex { .. } |
-                ProjectionElem::Subslice { .. } |
-                ProjectionElem::Downcast { .. } =>
-                    is_stable(&proj.base),
-            }
+    place.projection.iter().all(|elem| {
+        match elem {
+            // Which place this evaluates to can change with any memory write,
+            // so cannot assume this to be stable.
+            ProjectionElem::Deref => false,
+            // Array indices are intersting, but MIR building generates a *fresh*
+            // temporary for every array access, so the index cannot be changed as
+            // a side-effect.
+            ProjectionElem::Index { .. } |
+            // The rest is completely boring, they just offset by a constant.
+            ProjectionElem::Field { .. } |
+            ProjectionElem::ConstantIndex { .. } |
+            ProjectionElem::Subslice { .. } |
+            ProjectionElem::Downcast { .. } => true,
         }
-    }
+    })
 }
 
-/// Determine whether this type may have a reference in it, recursing below compound types but
-/// not below references.
-fn may_have_reference<'a, 'gcx, 'tcx>(ty: Ty<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool {
-    match ty.sty {
+/// Determine whether this type may be a reference (or box), and thus needs retagging.
+fn may_be_reference<'tcx>(ty: Ty<'tcx>) -> bool {
+    match ty.kind {
         // Primitive types that are not references
         ty::Bool | ty::Char |
         ty::Float(_) | ty::Int(_) | ty::Uint(_) |
@@ -60,35 +47,29 @@ fn may_have_reference<'a, 'gcx, 'tcx>(ty: Ty<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>)
         // References
         ty::Ref(..) => true,
         ty::Adt(..) if ty.is_box() => true,
-        // Compound types
-        ty::Array(ty, ..) | ty::Slice(ty) =>
-            may_have_reference(ty, tcx),
-        ty::Tuple(tys) =>
-            tys.iter().any(|ty| may_have_reference(ty, tcx)),
-        ty::Adt(adt, substs) =>
-            adt.variants.iter().any(|v| v.fields.iter().any(|f|
-                may_have_reference(f.ty(tcx, substs), tcx)
-            )),
+        // Compound types are not references
+        ty::Array(..) |
+        ty::Slice(..) |
+        ty::Tuple(..) |
+        ty::Adt(..) =>
+            false,
         // Conservative fallback
         _ => true,
     }
 }
 
-impl MirPass for AddRetag {
-    fn run_pass<'a, 'tcx>(&self,
-                          tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                          _src: MirSource<'tcx>,
-                          mir: &mut Mir<'tcx>)
-    {
+impl<'tcx> MirPass<'tcx> for AddRetag {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) {
         if !tcx.sess.opts.debugging_opts.mir_emit_retag {
             return;
         }
-        let (span, arg_count) = (mir.span, mir.arg_count);
-        let (basic_blocks, local_decls) = mir.basic_blocks_and_local_decls_mut();
+        let (span, arg_count) = (body.span, body.arg_count);
+        let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
         let needs_retag = |place: &Place<'tcx>| {
             // FIXME: Instead of giving up for unstable places, we should introduce
             // a temporary and retag on that.
-            is_stable(place) && may_have_reference(place.ty(&*local_decls, tcx).to_ty(tcx), tcx)
+            is_stable(place.as_ref())
+                && may_be_reference(place.ty(&*local_decls, tcx).ty)
         };
 
         // PART 1
@@ -101,14 +82,14 @@ impl MirPass for AddRetag {
             };
             // Gather all arguments, skip return value.
             let places = local_decls.iter_enumerated().skip(1).take(arg_count)
-                    .map(|(local, _)| Place::Local(local))
+                    .map(|(local, _)| Place::from(local))
                     .filter(needs_retag)
                     .collect::<Vec<_>>();
             // Emit their retags.
             basic_blocks[START_BLOCK].statements.splice(0..0,
                 places.into_iter().map(|place| Statement {
                     source_info,
-                    kind: StatementKind::Retag(RetagKind::FnEntry, place),
+                    kind: StatementKind::Retag(RetagKind::FnEntry, box(place)),
                 })
             );
         }
@@ -144,7 +125,7 @@ impl MirPass for AddRetag {
         for (source_info, dest_place, dest_block) in returns {
             basic_blocks[dest_block].statements.insert(0, Statement {
                 source_info,
-                kind: StatementKind::Retag(RetagKind::Default, dest_place),
+                kind: StatementKind::Retag(RetagKind::Default, box(dest_place)),
             });
         }
 
@@ -156,16 +137,16 @@ impl MirPass for AddRetag {
             for i in (0..block_data.statements.len()).rev() {
                 let (retag_kind, place) = match block_data.statements[i].kind {
                     // If we are casting *from* a reference, we may have to retag-as-raw.
-                    StatementKind::Assign(ref place, box Rvalue::Cast(
+                    StatementKind::Assign(box(ref place, Rvalue::Cast(
                         CastKind::Misc,
                         ref src,
                         dest_ty,
-                    )) => {
+                    ))) => {
                         let src_ty = src.ty(&*local_decls, tcx);
                         if src_ty.is_region_ptr() {
                             // The only `Misc` casts on references are those creating raw pointers.
                             assert!(dest_ty.is_unsafe_ptr());
-                            (RetagKind::Raw, place)
+                            (RetagKind::Raw, place.clone())
                         } else {
                             // Some other cast, no retag
                             continue
@@ -174,7 +155,7 @@ impl MirPass for AddRetag {
                     // Assignments of reference or ptr type are the ones where we may have
                     // to update tags.  This includes `x = &[mut] ...` and hence
                     // we also retag after taking a reference!
-                    StatementKind::Assign(ref place, box ref rvalue) if needs_retag(place) => {
+                    StatementKind::Assign(box(ref place, ref rvalue)) if needs_retag(place) => {
                         let kind = match rvalue {
                             Rvalue::Ref(_, borrow_kind, _)
                                 if borrow_kind.allows_two_phase_borrow()
@@ -183,7 +164,7 @@ impl MirPass for AddRetag {
                             _ =>
                                 RetagKind::Default,
                         };
-                        (kind, place)
+                        (kind, place.clone())
                     }
                     // Do nothing for the rest
                     _ => continue,
@@ -192,7 +173,7 @@ impl MirPass for AddRetag {
                 let source_info = block_data.statements[i].source_info;
                 block_data.statements.insert(i+1, Statement {
                     source_info,
-                    kind: StatementKind::Retag(retag_kind, place.clone()),
+                    kind: StatementKind::Retag(retag_kind, box(place)),
                 });
             }
         }