]> git.lizzy.rs Git - rust.git/commitdiff
rustc_mir: split off some qualify_consts::Checker fields into a State struct.
authorEduard-Mihai Burtescu <edy.burt@gmail.com>
Mon, 4 Feb 2019 21:24:20 +0000 (23:24 +0200)
committerEduard-Mihai Burtescu <edy.burt@gmail.com>
Thu, 14 Feb 2019 11:36:51 +0000 (13:36 +0200)
src/librustc_mir/transform/qualify_consts.rs

index 2cbe42721a3b17d6b32b338693d1479e93126f72..99b825b97a05ae78c8609d6f98e70ff03a87fc2b 100644 (file)
@@ -94,18 +94,31 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
-struct Checker<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+struct State {
+    local_qualif: IndexVec<Local, Option<Qualif>>,
+
+    qualif: Qualif,
+}
+
+impl State {
+    /// Add the given qualification to self.qualif.
+    fn add(&mut self, qualif: Qualif) {
+        self.qualif = self.qualif | qualif;
+    }
+}
+
+struct Checker<'a, 'gcx, 'tcx> {
+    tcx: TyCtxt<'a, 'gcx, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
     mode: Mode,
     span: Span,
     def_id: DefId,
     mir: &'a Mir<'tcx>,
     rpo: ReversePostorder<'a, 'tcx>,
-    tcx: TyCtxt<'a, 'gcx, 'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    local_qualif: IndexVec<Local, Option<Qualif>>,
-    qualif: Qualif,
+
+    state: State,
     temp_promotion_state: IndexVec<Local, TempState>,
-    promotion_candidates: Vec<Candidate>
+    promotion_candidates: Vec<Candidate>,
 }
 
 macro_rules! unleash_miri {
@@ -145,8 +158,10 @@ fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             rpo,
             tcx,
             param_env,
-            local_qualif,
-            qualif: Qualif::empty(),
+            state: State {
+                local_qualif,
+                qualif: Qualif::empty(),
+            },
             temp_promotion_state: temps,
             promotion_candidates: vec![]
         }
@@ -157,7 +172,7 @@ fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // slightly pointless (even with feature-gating).
     fn not_const(&mut self) {
         unleash_miri!(self);
-        self.add(Qualif::NOT_CONST);
+        self.state.add(Qualif::NOT_CONST);
         if self.mode != Mode::Fn {
             let mut err = struct_span_err!(
                 self.tcx.sess,
@@ -176,31 +191,26 @@ fn not_const(&mut self) {
         }
     }
 
-    /// Adds the given qualification to `self.qualif`.
-    fn add(&mut self, qualif: Qualif) {
-        self.qualif = self.qualif | qualif;
-    }
-
-    /// Adds the given type's qualification to `self.qualif`.
+    /// Adds the given type's qualification to self.state.qualif.
     fn add_type(&mut self, ty: Ty<'tcx>) {
-        self.add(Qualif::MUTABLE_INTERIOR | Qualif::NEEDS_DROP);
-        self.qualif.restrict(ty, self.tcx, self.param_env);
+        self.state.add(Qualif::MUTABLE_INTERIOR | Qualif::NEEDS_DROP);
+        self.state.qualif.restrict(ty, self.tcx, self.param_env);
     }
 
-    /// Within the provided closure, `self.qualif` will start
+    /// Within the provided closure, `self.state.qualif` will start
     /// out empty, and its value after the closure returns will
     /// be combined with the value before the call to nest.
     fn nest<F: FnOnce(&mut Self)>(&mut self, f: F) {
-        let original = self.qualif;
-        self.qualif = Qualif::empty();
+        let original = self.state.qualif;
+        self.state.qualif = Qualif::empty();
         f(self);
-        self.add(original);
+        self.state.add(original);
     }
 
     /// Assign the current qualification to the given destination.
     fn assign(&mut self, dest: &Place<'tcx>, location: Location) {
         trace!("assign: {:?}", dest);
-        let qualif = self.qualif;
+        let qualif = self.state.qualif;
         let span = self.span;
         let store = |slot: &mut Option<Qualif>| {
             if slot.is_some() {
@@ -215,7 +225,7 @@ fn assign(&mut self, dest: &Place<'tcx>, location: Location) {
                 if self.mir.local_kind(index) == LocalKind::Temp
                 && self.temp_promotion_state[index].is_promotable() {
                     debug!("store to promotable temp {:?} ({:?})", index, qualif);
-                    store(&mut self.local_qualif[index]);
+                    store(&mut self.state.local_qualif[index]);
                 }
             }
             return;
@@ -253,14 +263,14 @@ fn assign(&mut self, dest: &Place<'tcx>, location: Location) {
             }
         };
         debug!("store to var {:?}", index);
-        match &mut self.local_qualif[index] {
+        match &mut self.state.local_qualif[index] {
             // this is overly restrictive, because even full assignments do not clear the qualif
             // While we could special case full assignments, this would be inconsistent with
             // aggregates where we overwrite all fields via assignments, which would not get
             // that feature.
-            Some(ref mut qualif) => *qualif = *qualif | self.qualif,
+            Some(ref mut qualif) => *qualif = *qualif | self.state.qualif,
             // insert new qualification
-            qualif @ None => *qualif = Some(self.qualif),
+            qualif @ None => *qualif = Some(self.state.qualif),
         }
     }
 
@@ -317,12 +327,12 @@ fn check_const(&mut self) -> (Qualif, Lrc<BitSet<Local>>) {
             }
         }
 
-        self.qualif = self.local_qualif[RETURN_PLACE].unwrap_or(Qualif::NOT_CONST);
+        self.state.qualif = self.state.local_qualif[RETURN_PLACE].unwrap_or(Qualif::NOT_CONST);
 
         // Account for errors in consts by using the
         // conservative type qualification instead.
-        if self.qualif.intersects(Qualif::CONST_ERROR) {
-            self.qualif = Qualif::empty();
+        if self.state.qualif.intersects(Qualif::CONST_ERROR) {
+            self.state.qualif = Qualif::empty();
             let return_ty = mir.return_ty();
             self.add_type(return_ty);
         }
@@ -346,7 +356,7 @@ fn check_const(&mut self) -> (Qualif, Lrc<BitSet<Local>>) {
             }
         }
 
-        (self.qualif, Lrc::new(promoted_temps))
+        (self.state.qualif, Lrc::new(promoted_temps))
     }
 
     fn is_const_panic_fn(&self, def_id: DefId) -> bool {
@@ -355,7 +365,7 @@ fn is_const_panic_fn(&self, def_id: DefId) -> bool {
     }
 }
 
-/// Accumulates an Rvalue or Call's effects in self.qualif.
+/// Accumulates an Rvalue or Call's effects in self.state.qualif.
 /// For functions (constant or not), it also records
 /// candidates for promotion in promotion_candidates.
 impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
@@ -370,22 +380,22 @@ fn visit_local(&mut self,
                 self.not_const();
             }
             LocalKind::Var if self.mode == Mode::Fn => {
-                self.add(Qualif::NOT_CONST);
+                self.state.add(Qualif::NOT_CONST);
             }
             LocalKind::Var |
             LocalKind::Arg |
             LocalKind::Temp => {
                 if let LocalKind::Arg = kind {
-                    self.add(Qualif::FN_ARGUMENT);
+                    self.state.add(Qualif::FN_ARGUMENT);
                 }
 
                 if !self.temp_promotion_state[local].is_promotable() {
                     debug!("visit_local: (not promotable) local={:?}", local);
-                    self.add(Qualif::NOT_PROMOTABLE);
+                    self.state.add(Qualif::NOT_PROMOTABLE);
                 }
 
-                if let Some(qualif) = self.local_qualif[local] {
-                    self.add(qualif);
+                if let Some(qualif) = self.state.local_qualif[local] {
+                    self.state.add(qualif);
                 } else {
                     self.not_const();
                 }
@@ -411,7 +421,7 @@ fn visit_place(&mut self,
                                   "thread-local statics cannot be \
                                    accessed at compile-time");
                     }
-                    self.add(Qualif::NOT_CONST);
+                    self.state.add(Qualif::NOT_CONST);
                     return;
                 }
 
@@ -430,7 +440,7 @@ fn visit_place(&mut self,
                     return;
                 }
                 unleash_miri!(self);
-                self.add(Qualif::NOT_CONST);
+                self.state.add(Qualif::NOT_CONST);
 
                 if self.mode != Mode::Fn {
                     let mut err = struct_span_err!(self.tcx.sess, self.span, E0013,
@@ -458,7 +468,7 @@ fn visit_place(&mut self,
                                 this.not_const()
                             } else {
                                 // just make sure this doesn't get promoted
-                                this.add(Qualif::NOT_CONST);
+                                this.state.add(Qualif::NOT_CONST);
                             }
                             let base_ty = proj.base.ty(this.mir, this.tcx).to_ty(this.tcx);
                             match this.mode {
@@ -508,7 +518,7 @@ fn visit_place(&mut self,
                             }
 
                             let ty = place.ty(this.mir, this.tcx).to_ty(this.tcx);
-                            this.qualif.restrict(ty, this.tcx, this.param_env);
+                            this.state.qualif.restrict(ty, this.tcx, this.param_env);
                         }
 
                         ProjectionElem::Downcast(..) => {
@@ -529,7 +539,7 @@ fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
             Operand::Move(_) => {
                 // Mark the consumed locals to indicate later drops are noops.
                 if let Operand::Move(Place::Local(local)) = *operand {
-                    self.local_qualif[local] = self.local_qualif[local].map(|q|
+                    self.state.local_qualif[local] = self.state.local_qualif[local].map(|q|
                         q - Qualif::NEEDS_DROP
                     );
                 }
@@ -543,12 +553,12 @@ fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
                         let (bits, _) = self.tcx.at(constant.span).mir_const_qualif(*def_id);
 
                         let qualif = Qualif::from_bits(bits).expect("invalid mir_const_qualif");
-                        self.add(qualif);
+                        self.state.add(qualif);
 
                         // Just in case the type is more specific than
                         // the definition, e.g., impl associated const
                         // with type parameters, take it into account.
-                        self.qualif.restrict(constant.ty, self.tcx, self.param_env);
+                        self.state.qualif.restrict(constant.ty, self.tcx, self.param_env);
                     }
                 }
             }
@@ -630,7 +640,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
 
                     if forbidden_mut {
                         unleash_miri!(self);
-                        self.add(Qualif::NOT_CONST);
+                        self.state.add(Qualif::NOT_CONST);
                         if self.mode != Mode::Fn {
                             let mut err = struct_span_err!(self.tcx.sess,  self.span, E0017,
                                                            "references in {}s may only refer \
@@ -654,11 +664,11 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
                     // Constants cannot be borrowed if they contain interior mutability as
                     // it means that our "silent insertion of statics" could change
                     // initializer values (very bad).
-                    if self.qualif.contains(Qualif::MUTABLE_INTERIOR) {
+                    if self.state.qualif.contains(Qualif::MUTABLE_INTERIOR) {
                         // A reference of a MUTABLE_INTERIOR place is instead
                         // NOT_CONST (see `if forbidden_mut` below), to avoid
                         // duplicate errors (from reborrowing, for example).
-                        self.qualif = self.qualif - Qualif::MUTABLE_INTERIOR;
+                        self.state.qualif = self.state.qualif - Qualif::MUTABLE_INTERIOR;
                         if self.mode != Mode::Fn {
                             span_err!(self.tcx.sess, self.span, E0492,
                                       "cannot borrow a constant which may contain \
@@ -673,7 +683,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
                 debug!("visit_rvalue: forbidden_mut={:?}", forbidden_mut);
                 if forbidden_mut {
                     unleash_miri!(self);
-                    self.add(Qualif::NOT_CONST);
+                    self.state.add(Qualif::NOT_CONST);
                 } else {
                     // We might have a candidate for promotion.
                     let candidate = Candidate::Ref(location);
@@ -689,7 +699,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
                     if let Place::Local(local) = *place {
                         if self.mir.local_kind(local) == LocalKind::Temp {
                             debug!("visit_rvalue: local={:?}", local);
-                            if let Some(qualif) = self.local_qualif[local] {
+                            if let Some(qualif) = self.state.local_qualif[local] {
                                 // `forbidden_mut` is false, so we can safely ignore
                                 // `MUTABLE_INTERIOR` from the local's qualifications.
                                 // This allows borrowing fields which don't have
@@ -716,7 +726,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
                         unleash_miri!(self);
                         if let Mode::Fn = self.mode {
                             // in normal functions, mark such casts as not promotable
-                            self.add(Qualif::NOT_CONST);
+                            self.state.add(Qualif::NOT_CONST);
                         } else if !self.tcx.features().const_raw_ptr_to_usize_cast {
                             // in const fn and constants require the feature gate
                             // FIXME: make it unsafe inside const fn and constants
@@ -744,7 +754,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
                     unleash_miri!(self);
                     if let Mode::Fn = self.mode {
                         // raw pointer operations are not allowed inside promoteds
-                        self.add(Qualif::NOT_CONST);
+                        self.state.add(Qualif::NOT_CONST);
                     } else if !self.tcx.features().const_compare_raw_pointers {
                         // require the feature gate inside constants and const fn
                         // FIXME: make it unsafe to use these operations
@@ -761,7 +771,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
 
             Rvalue::NullaryOp(NullOp::Box, _) => {
                 unleash_miri!(self);
-                self.add(Qualif::NOT_CONST);
+                self.state.add(Qualif::NOT_CONST);
                 if self.mode != Mode::Fn {
                     let mut err = struct_span_err!(self.tcx.sess, self.span, E0010,
                                                    "allocations are not allowed in {}s", self.mode);
@@ -781,13 +791,13 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
             Rvalue::Aggregate(ref kind, _) => {
                 if let AggregateKind::Adt(def, ..) = **kind {
                     if def.has_dtor(self.tcx) {
-                        self.add(Qualif::NEEDS_DROP);
+                        self.state.add(Qualif::NEEDS_DROP);
                     }
 
                     if Some(def.did) == self.tcx.lang_items().unsafe_cell_type() {
                         let ty = rvalue.ty(self.mir, self.tcx);
                         self.add_type(ty);
-                        assert!(self.qualif.contains(Qualif::MUTABLE_INTERIOR));
+                        assert!(self.state.qualif.contains(Qualif::MUTABLE_INTERIOR));
                     }
                 }
             }
@@ -983,7 +993,7 @@ fn visit_terminator_kind(&mut self,
                     }
                     let candidate = Candidate::Argument { bb, index: i };
                     if is_shuffle && i == 2 {
-                        if this.qualif.is_empty() {
+                        if this.state.qualif.is_empty() {
                             debug!("visit_terminator_kind: candidate={:?}", candidate);
                             this.promotion_candidates.push(candidate);
                         } else {
@@ -1010,7 +1020,7 @@ fn visit_terminator_kind(&mut self,
                     // which happens even without the user requesting it.
                     // We can error out with a hard error if the argument is not
                     // constant here.
-                    if (this.qualif - Qualif::NOT_PROMOTABLE).is_empty() {
+                    if (this.state.qualif - Qualif::NOT_PROMOTABLE).is_empty() {
                         debug!("visit_terminator_kind: candidate={:?}", candidate);
                         this.promotion_candidates.push(candidate);
                     } else {
@@ -1023,7 +1033,7 @@ fn visit_terminator_kind(&mut self,
 
             // non-const fn calls
             if !is_const_fn {
-                self.qualif = Qualif::NOT_CONST;
+                self.state.qualif = Qualif::NOT_CONST;
                 if self.mode != Mode::Fn {
                     self.tcx.sess.delay_span_bug(
                         self.span,
@@ -1034,16 +1044,16 @@ fn visit_terminator_kind(&mut self,
 
             if let Some((ref dest, _)) = *destination {
                 // Avoid propagating irrelevant callee/argument qualifications.
-                if self.qualif.intersects(Qualif::CONST_ERROR) {
-                    self.qualif = Qualif::NOT_CONST;
+                if self.state.qualif.intersects(Qualif::CONST_ERROR) {
+                    self.state.qualif = Qualif::NOT_CONST;
                 } else {
                     // Be conservative about the returned value of a const fn.
                     let tcx = self.tcx;
                     let ty = dest.ty(self.mir, tcx).to_ty(tcx);
                     if is_const_fn && !is_promotable_const_fn && self.mode == Mode::Fn {
-                        self.qualif = Qualif::NOT_PROMOTABLE;
+                        self.state.qualif = Qualif::NOT_PROMOTABLE;
                     } else {
-                        self.qualif = Qualif::empty();
+                        self.state.qualif = Qualif::empty();
                     }
                     self.add_type(ty);
                 }
@@ -1058,7 +1068,9 @@ fn visit_terminator_kind(&mut self,
                 // HACK(eddyb): emulate a bit of dataflow analysis,
                 // conservatively, that drop elaboration will do.
                 let needs_drop = if let Place::Local(local) = *place {
-                    if self.local_qualif[local].map_or(true, |q| q.contains(Qualif::NEEDS_DROP)) {
+                    let local_needs_drop = self.state.local_qualif[local]
+                        .map_or(true, |q| q.contains(Qualif::NEEDS_DROP));
+                    if local_needs_drop {
                         Some(self.mir.local_decls[local].source_info.span)
                     } else {
                         None