about summary refs log tree commit diff
path: root/src/librustc_mir/transform
diff options
context:
space:
mode:
authorEduard-Mihai Burtescu <edy.burt@gmail.com>2019-02-06 03:08:43 +0200
committerEduard-Mihai Burtescu <edy.burt@gmail.com>2019-02-14 13:36:51 +0200
commit1d6332def3c3091ba3287e5d473f80443dc0a882 (patch)
treed605cf9affa7e7363eb68f774c48a8505dab2381 /src/librustc_mir/transform
parent2de5b389435d97fbb547c7393f400702f109594e (diff)
downloadrust-1d6332def3c3091ba3287e5d473f80443dc0a882.tar.gz
rust-1d6332def3c3091ba3287e5d473f80443dc0a882.zip
rustc_mir: avoid having an Option around each local qualification in qualify_consts.
Diffstat (limited to 'src/librustc_mir/transform')
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs107
1 files changed, 48 insertions, 59 deletions
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index f0fd598d31b..25d201c3452 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -117,8 +117,7 @@ struct Qualifier<'a, 'tcx> {
     mode: Mode,
     mir: &'a Mir<'tcx>,
 
-    local_qualif: &'a IndexVec<Local, Option<Qualif>>,
-    temp_promotion_state: &'a IndexVec<Local, TempState>,
+    local_qualif: &'a IndexVec<Local, Qualif>,
 }
 
 impl<'a, 'tcx> Qualifier<'a, 'tcx> {
@@ -127,24 +126,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx> {
     }
 
     fn qualify_local(&self, local: Local) -> Qualif {
-        let kind = self.mir.local_kind(local);
-        match kind {
-            LocalKind::ReturnPointer => Qualif::NOT_CONST,
-            LocalKind::Var if self.mode == Mode::Fn => Qualif::NOT_CONST,
-
-            LocalKind::Var |
-            LocalKind::Arg |
-            LocalKind::Temp => {
-                let mut qualif = self.local_qualif[local]
-                    .unwrap_or(Qualif::NOT_CONST);
-
-                if !self.temp_promotion_state[local].is_promotable() {
-                    qualif = qualif | Qualif::NOT_PROMOTABLE;
-                }
-
-                qualif
-            }
-        }
+        self.local_qualif[local]
     }
 
     fn qualify_projection_elem(&self, proj: &PlaceElem<'tcx>) -> Qualif {
@@ -467,7 +449,7 @@ struct Checker<'a, 'tcx> {
     mir: &'a Mir<'tcx>,
     rpo: ReversePostorder<'a, 'tcx>,
 
-    local_qualif: IndexVec<Local, Option<Qualif>>,
+    local_qualif: IndexVec<Local, Qualif>,
     temp_promotion_state: IndexVec<Local, TempState>,
     promotion_candidates: Vec<Candidate>,
 }
@@ -494,11 +476,22 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
 
         let param_env = tcx.param_env(def_id);
 
-        let mut local_qualif = IndexVec::from_elem(None, &mir.local_decls);
-        for arg in mir.args_iter() {
-            let qualif = Qualif::any_value_of_ty(mir.local_decls[arg].ty, tcx, param_env);
-            local_qualif[arg] = Some(Qualif::NOT_PROMOTABLE | qualif);
-        }
+        let local_qualif = mir.local_decls.iter_enumerated().map(|(local, decl)| {
+            match mir.local_kind(local) {
+                LocalKind::Arg => {
+                    Qualif::any_value_of_ty(decl.ty, tcx, param_env) |
+                        Qualif::NOT_PROMOTABLE
+                }
+
+                LocalKind::Var if mode == Mode::Fn => Qualif::NOT_CONST,
+
+                LocalKind::Temp if !temps[local].is_promotable() => {
+                    Qualif::NOT_PROMOTABLE
+                }
+
+                _ => Qualif::empty(),
+            }
+        }).collect();
 
         Checker {
             mode,
@@ -521,7 +514,6 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
             mode: self.mode,
             mir: self.mir,
             local_qualif: &self.local_qualif,
-            temp_promotion_state: &self.temp_promotion_state,
         }
     }
 
@@ -559,10 +551,10 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
                 && self.temp_promotion_state[index].is_promotable() {
                     debug!("store to promotable temp {:?} ({:?})", index, qualif);
                     let slot = &mut self.local_qualif[index];
-                    if slot.is_some() {
+                    if !slot.is_empty() {
                         span_bug!(self.span, "multiple assignments to {:?}", dest);
                     }
-                    *slot = Some(qualif);
+                    *slot = qualif;
                 }
             }
             return;
@@ -605,7 +597,18 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
         // aggregates where we overwrite all fields via assignments, which would not get
         // that feature.
         let slot = &mut self.local_qualif[index];
-        *slot = Some(slot.unwrap_or(Qualif::empty()) | qualif);
+        *slot = *slot | qualif;
+
+        // Ensure we keep the `NOT_PROMOTABLE` flag is preserved.
+        // NOTE(eddyb) this is actually unnecessary right now, as
+        // we never replace the local's qualif (but we might in
+        // the future) - also, if `NOT_PROMOTABLE` only matters
+        // for `Mode::Fn`, then this is also pointless.
+        if self.mir.local_kind(index) == LocalKind::Temp {
+            if !self.temp_promotion_state[index].is_promotable() {
+                *slot = *slot | Qualif::NOT_PROMOTABLE;
+            }
+        }
     }
 
     /// Check a whole const, static initializer or const fn.
@@ -661,7 +664,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
             }
         }
 
-        let mut qualif = self.local_qualif[RETURN_PLACE].unwrap_or(Qualif::NOT_CONST);
+        let mut qualif = self.local_qualif[RETURN_PLACE];
 
         // Account for errors in consts by using the
         // conservative type qualification instead.
@@ -698,16 +701,6 @@ 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_local(&mut self,
-                   &local: &Local,
-                   _: PlaceContext<'tcx>,
-                   _: Location) {
-        debug!("visit_local: local={:?}", local);
-        if self.local_qualif[local].is_none() {
-            self.not_const();
-        }
-    }
-
     fn visit_place(&mut self,
                     place: &Place<'tcx>,
                     context: PlaceContext<'tcx>,
@@ -833,9 +826,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
             Operand::Move(ref place) => {
                 // Mark the consumed locals to indicate later drops are noops.
                 if let Place::Local(local) = *place {
-                    self.local_qualif[local] = self.local_qualif[local].map(|q|
-                        q - Qualif::NEEDS_DROP
-                    );
+                    let slot = &mut self.local_qualif[local];
+                    *slot = *slot - Qualif::NEEDS_DROP;
                 }
             }
             Operand::Copy(_) |
@@ -1137,9 +1129,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
                 // HACK(eddyb): emulate a bit of dataflow analysis,
                 // conservatively, that drop elaboration will do.
                 let needs_drop = if let Place::Local(local) = *place {
-                    let local_needs_drop = self.local_qualif[local]
-                        .map_or(true, |q| q.contains(Qualif::NEEDS_DROP));
-                    if local_needs_drop {
+                    if self.local_qualif[local].contains(Qualif::NEEDS_DROP) {
                         Some(self.mir.local_decls[local].source_info.span)
                     } else {
                         None
@@ -1223,18 +1213,17 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
                 if let Place::Local(local) = *place {
                     if self.mir.local_kind(local) == LocalKind::Temp {
                         debug!("qualify_consts: promotion candidate: local={:?}", local);
-                        if let Some(qualif) = self.local_qualif[local] {
-                            // The borrowed place doesn't have `MUTABLE_INTERIOR`
-                            // (from `qualify_rvalue`), so we can safely ignore
-                            // `MUTABLE_INTERIOR` from the local's qualifications.
-                            // This allows borrowing fields which don't have
-                            // `MUTABLE_INTERIOR`, from a type that does, e.g.:
-                            // `let _: &'static _ = &(Cell::new(1), 2).1;`
-                            debug!("qualify_consts: promotion candidate: qualif={:?}", qualif);
-                            if (qualif - Qualif::MUTABLE_INTERIOR).is_empty() {
-                                debug!("qualify_consts: promotion candidate: {:?}", candidate);
-                                self.promotion_candidates.push(candidate);
-                            }
+                        let qualif = self.local_qualif[local];
+                        // The borrowed place doesn't have `MUTABLE_INTERIOR`
+                        // (from `qualify_rvalue`), so we can safely ignore
+                        // `MUTABLE_INTERIOR` from the local's qualifications.
+                        // This allows borrowing fields which don't have
+                        // `MUTABLE_INTERIOR`, from a type that does, e.g.:
+                        // `let _: &'static _ = &(Cell::new(1), 2).1;`
+                        debug!("qualify_consts: promotion candidate: qualif={:?}", qualif);
+                        if (qualif - Qualif::MUTABLE_INTERIOR).is_empty() {
+                            debug!("qualify_consts: promotion candidate: {:?}", candidate);
+                            self.promotion_candidates.push(candidate);
                         }
                     }
                 }