about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/mir/visit.rs24
-rw-r--r--src/librustc_mir/transform/generator.rs28
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs222
3 files changed, 155 insertions, 119 deletions
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 2f19f591830..ce015631cd1 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -160,8 +160,9 @@ macro_rules! make_mir_visitor {
 
             fn visit_projection(&mut self,
                                 place: & $($mutability)? Projection<'tcx>,
+                                context: PlaceContext,
                                 location: Location) {
-                self.super_projection(place, location);
+                self.super_projection(place, context, location);
             }
 
             fn visit_constant(&mut self,
@@ -686,8 +687,7 @@ macro_rules! make_mir_visitor {
                             PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
                         };
 
-                        self.visit_place(& $($mutability)? proj.base, context, location);
-                        self.visit_projection(proj, location);
+                        self.visit_projection(proj, context, location);
                     }
                 }
             }
@@ -708,7 +708,25 @@ macro_rules! make_mir_visitor {
 
             fn super_projection(&mut self,
                                 proj: & $($mutability)? Projection<'tcx>,
+                                context: PlaceContext,
                                 location: Location) {
+                // this is duplicated with `super_place` in preparation for changing `Place` to be
+                // a struct with a base and a slice of projections. `visit_place` should only ever
+                // be called for the base place now.
+                match & $($mutability)? proj.base {
+                    Place::Base(place_base) => {
+                        self.visit_place_base(place_base, context, location);
+                    }
+                    Place::Projection(proj) => {
+                        let context = if context.is_mutating_use() {
+                            PlaceContext::MutatingUse(MutatingUseContext::Projection)
+                        } else {
+                            PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
+                        };
+
+                        self.visit_projection(proj, context, location);
+                    }
+                }
                 match & $($mutability)? proj.elem {
                     ProjectionElem::Deref => {
                     }
diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index f36ede4e8d9..35640e9a45e 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -103,11 +103,11 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor {
                     place: &mut Place<'tcx>,
                     context: PlaceContext,
                     location: Location) {
-        if *place == Place::Base(PlaceBase::Local(self_arg())) {
-            *place = Place::Projection(Box::new(Projection {
-                base: place.clone(),
+        if place.base_local() == Some(self_arg()) {
+            replace_base(place, Place::Projection(Box::new(Projection {
+                base: Place::Base(PlaceBase::Local(self_arg())),
                 elem: ProjectionElem::Deref,
-            }));
+            })));
         } else {
             self.super_place(place, context, location);
         }
@@ -130,17 +130,25 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
                     place: &mut Place<'tcx>,
                     context: PlaceContext,
                     location: Location) {
-        if *place == Place::Base(PlaceBase::Local(self_arg())) {
-            *place = Place::Projection(Box::new(Projection {
-                base: place.clone(),
+        if place.base_local() == Some(self_arg()) {
+            replace_base(place, Place::Projection(Box::new(Projection {
+                base: Place::Base(PlaceBase::Local(self_arg())),
                 elem: ProjectionElem::Field(Field::new(0), self.ref_gen_ty),
-            }));
+            })));
         } else {
             self.super_place(place, context, location);
         }
     }
 }
 
+fn replace_base(place: &mut Place<'tcx>, new_base: Place<'tcx>) {
+    if let Place::Projection(proj) = place {
+        replace_base(&mut proj.base, new_base);
+    } else {
+        *place = new_base;
+    }
+}
+
 fn self_arg() -> Local {
     Local::new(1)
 }
@@ -236,10 +244,10 @@ impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> {
                     place: &mut Place<'tcx>,
                     context: PlaceContext,
                     location: Location) {
-        if let Place::Base(PlaceBase::Local(l)) = *place {
+        if let Some(l) = place.base_local() {
             // Replace an Local in the remap with a generator struct access
             if let Some(&(ty, variant_index, idx)) = self.remap.get(&l) {
-                *place = self.make_field(variant_index, idx, ty);
+                replace_base(place, self.make_field(variant_index, idx, ty));
             }
         } else {
             self.super_place(place, context, location);
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 8696291e058..64aecee6337 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -926,125 +926,135 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
 /// For functions (constant or not), it also records
 /// candidates for promotion in `promotion_candidates`.
 impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
-    fn visit_place(&mut self,
-                    place: &Place<'tcx>,
-                    context: PlaceContext,
-                    location: Location) {
-        debug!("visit_place: place={:?} context={:?} location={:?}", place, context, location);
-        place.iterate(|place_base, place_projections| {
-            match place_base {
-                PlaceBase::Local(_) => {}
-                PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. }) => {
-                    unreachable!()
-                }
-                PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. }) => {
-                    if self.tcx
-                           .get_attrs(*def_id)
-                           .iter()
-                           .any(|attr| attr.check_name(sym::thread_local)) {
-                        if self.mode != Mode::Fn {
-                            span_err!(self.tcx.sess, self.span, E0625,
-                                      "thread-local statics cannot be \
-                                       accessed at compile-time");
-                        }
-                        return;
+    fn visit_place_base(
+        &mut self,
+        place_base: &PlaceBase<'tcx>,
+        context: PlaceContext,
+        location: Location,
+    ) {
+        self.super_place_base(place_base, context, location);
+        match place_base {
+            PlaceBase::Local(_) => {}
+            PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. }) => {
+                unreachable!()
+            }
+            PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. }) => {
+                if self.tcx
+                        .get_attrs(*def_id)
+                        .iter()
+                        .any(|attr| attr.check_name(sym::thread_local)) {
+                    if self.mode != Mode::Fn {
+                        span_err!(self.tcx.sess, self.span, E0625,
+                                    "thread-local statics cannot be \
+                                    accessed at compile-time");
                     }
+                    return;
+                }
 
-                    // Only allow statics (not consts) to refer to other statics.
-                    if self.mode == Mode::Static || self.mode == Mode::StaticMut {
-                        if self.mode == Mode::Static && context.is_mutating_use() {
-                            // this is not strictly necessary as miri will also bail out
-                            // For interior mutability we can't really catch this statically as that
-                            // goes through raw pointers and intermediate temporaries, so miri has
-                            // to catch this anyway
-                            self.tcx.sess.span_err(
-                                self.span,
-                                "cannot mutate statics in the initializer of another static",
-                            );
-                        }
-                        return;
+                // Only allow statics (not consts) to refer to other statics.
+                if self.mode == Mode::Static || self.mode == Mode::StaticMut {
+                    if self.mode == Mode::Static && context.is_mutating_use() {
+                        // this is not strictly necessary as miri will also bail out
+                        // For interior mutability we can't really catch this statically as that
+                        // goes through raw pointers and intermediate temporaries, so miri has
+                        // to catch this anyway
+                        self.tcx.sess.span_err(
+                            self.span,
+                            "cannot mutate statics in the initializer of another static",
+                        );
                     }
-                    unleash_miri!(self);
+                    return;
+                }
+                unleash_miri!(self);
 
-                    if self.mode != Mode::Fn {
-                        let mut err = struct_span_err!(self.tcx.sess, self.span, E0013,
-                                                       "{}s cannot refer to statics, use \
-                                                        a constant instead", self.mode);
-                        if self.tcx.sess.teach(&err.get_code().unwrap()) {
-                            err.note(
-                                "Static and const variables can refer to other const variables. \
-                                 But a const variable cannot refer to a static variable."
-                            );
-                            err.help(
-                                "To fix this, the value can be extracted as a const and then used."
-                            );
-                        }
-                        err.emit()
+                if self.mode != Mode::Fn {
+                    let mut err = struct_span_err!(self.tcx.sess, self.span, E0013,
+                                                    "{}s cannot refer to statics, use \
+                                                    a constant instead", self.mode);
+                    if self.tcx.sess.teach(&err.get_code().unwrap()) {
+                        err.note(
+                            "Static and const variables can refer to other const variables. \
+                                But a const variable cannot refer to a static variable."
+                        );
+                        err.help(
+                            "To fix this, the value can be extracted as a const and then used."
+                        );
                     }
+                    err.emit()
                 }
             }
+        }
+    }
 
-            for proj in place_projections {
-                match proj.elem {
-                    ProjectionElem::Deref => {
-                        if context.is_mutating_use() {
-                            // `not_const` errors out in const contexts
-                            self.not_const()
-                        }
-                        let base_ty = proj.base.ty(self.mir, self.tcx).ty;
-                        match self.mode {
-                            Mode::Fn => {},
-                            _ => {
-                                if let ty::RawPtr(_) = base_ty.sty {
-                                    if !self.tcx.features().const_raw_ptr_deref {
-                                        emit_feature_err(
-                                            &self.tcx.sess.parse_sess, sym::const_raw_ptr_deref,
-                                            self.span, GateIssue::Language,
-                                            &format!(
-                                                "dereferencing raw pointers in {}s is unstable",
-                                                self.mode,
-                                            ),
-                                        );
-                                    }
-                                }
+    fn visit_projection(
+        &mut self,
+        proj: &Projection<'tcx>,
+        context: PlaceContext,
+        location: Location,
+    ) {
+        debug!(
+            "visit_place_projection: proj={:?} context={:?} location={:?}",
+            proj, context, location,
+        );
+        self.super_projection(proj, context, location);
+        match proj.elem {
+            ProjectionElem::Deref => {
+                if context.is_mutating_use() {
+                    // `not_const` errors out in const contexts
+                    self.not_const()
+                }
+                let base_ty = proj.base.ty(self.mir, self.tcx).ty;
+                match self.mode {
+                    Mode::Fn => {},
+                    _ => {
+                        if let ty::RawPtr(_) = base_ty.sty {
+                            if !self.tcx.features().const_raw_ptr_deref {
+                                emit_feature_err(
+                                    &self.tcx.sess.parse_sess, sym::const_raw_ptr_deref,
+                                    self.span, GateIssue::Language,
+                                    &format!(
+                                        "dereferencing raw pointers in {}s is unstable",
+                                        self.mode,
+                                    ),
+                                );
                             }
                         }
                     }
+                }
+            }
 
-                    ProjectionElem::ConstantIndex {..} |
-                    ProjectionElem::Subslice {..} |
-                    ProjectionElem::Field(..) |
-                    ProjectionElem::Index(_) => {
-                        let base_ty = proj.base.ty(self.mir, self.tcx).ty;
-                        if let Some(def) = base_ty.ty_adt_def() {
-                            if def.is_union() {
-                                match self.mode {
-                                    Mode::ConstFn => {
-                                        if !self.tcx.features().const_fn_union {
-                                            emit_feature_err(
-                                                &self.tcx.sess.parse_sess, sym::const_fn_union,
-                                                self.span, GateIssue::Language,
-                                                "unions in const fn are unstable",
-                                            );
-                                        }
-                                    },
-
-                                    | Mode::Fn
-                                    | Mode::Static
-                                    | Mode::StaticMut
-                                    | Mode::Const
-                                    => {},
+            ProjectionElem::ConstantIndex {..} |
+            ProjectionElem::Subslice {..} |
+            ProjectionElem::Field(..) |
+            ProjectionElem::Index(_) => {
+                let base_ty = proj.base.ty(self.mir, self.tcx).ty;
+                if let Some(def) = base_ty.ty_adt_def() {
+                    if def.is_union() {
+                        match self.mode {
+                            Mode::ConstFn => {
+                                if !self.tcx.features().const_fn_union {
+                                    emit_feature_err(
+                                        &self.tcx.sess.parse_sess, sym::const_fn_union,
+                                        self.span, GateIssue::Language,
+                                        "unions in const fn are unstable",
+                                    );
                                 }
-                            }
-                        }
-                    }
+                            },
 
-                    ProjectionElem::Downcast(..) => {
-                        self.not_const()
+                            | Mode::Fn
+                            | Mode::Static
+                            | Mode::StaticMut
+                            | Mode::Const
+                            => {},
+                        }
                     }
                 }
             }
-        });
+
+            ProjectionElem::Downcast(..) => {
+                self.not_const()
+            }
+        }
     }
 
     fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
@@ -1069,17 +1079,17 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
         // Check nested operands and places.
         if let Rvalue::Ref(_, kind, ref place) = *rvalue {
             // Special-case reborrows.
-            let mut is_reborrow = false;
+            let mut reborrow_place = None;
             if let Place::Projection(ref proj) = *place {
                 if let ProjectionElem::Deref = proj.elem {
                     let base_ty = proj.base.ty(self.mir, self.tcx).ty;
                     if let ty::Ref(..) = base_ty.sty {
-                        is_reborrow = true;
+                        reborrow_place = Some(&proj.base);
                     }
                 }
             }
 
-            if is_reborrow {
+            if let Some(place) = reborrow_place {
                 let ctx = match kind {
                     BorrowKind::Shared => PlaceContext::NonMutatingUse(
                         NonMutatingUseContext::SharedBorrow,
@@ -1094,7 +1104,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
                         MutatingUseContext::Borrow,
                     ),
                 };
-                self.super_place(place, ctx, location);
+                self.visit_place(place, ctx, location);
             } else {
                 self.super_rvalue(rvalue, location);
             }