about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSaleem Jaffer <saleem@acko.com>2019-03-16 17:40:41 +0530
committerSaleem Jaffer <saleem@acko.com>2019-03-18 15:03:29 +0530
commit7fb1c22da181426f6ea7662f5c7f47edbbe24f56 (patch)
treefe473b57dc513f00eb6a140124cdcf1ce150398e
parent03dafa7da38decbe74fcd8a23d7ec835e637c8e4 (diff)
downloadrust-7fb1c22da181426f6ea7662f5c7f47edbbe24f56.tar.gz
rust-7fb1c22da181426f6ea7662f5c7f47edbbe24f56.zip
promoted is still left in 2 places
-rw-r--r--src/librustc/mir/mod.rs37
-rw-r--r--src/librustc/mir/tcx.rs1
-rw-r--r--src/librustc/mir/visit.rs15
-rw-r--r--src/librustc_mir/borrow_check/error_reporting.rs17
-rw-r--r--src/librustc_mir/borrow_check/mod.rs56
-rw-r--r--src/librustc_mir/borrow_check/mutability_errors.rs23
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs92
-rw-r--r--src/librustc_mir/borrow_check/path_utils.rs1
-rw-r--r--src/librustc_mir/borrow_check/place_ext.rs10
-rw-r--r--src/librustc_mir/borrow_check/places_conflict.rs67
-rw-r--r--src/librustc_mir/borrow_check/prefixes.rs2
-rw-r--r--src/librustc_mir/build/expr/as_place.rs1
-rw-r--r--src/librustc_mir/dataflow/impls/borrowed_locals.rs1
-rw-r--r--src/librustc_mir/dataflow/move_paths/builder.rs1
-rw-r--r--src/librustc_mir/dataflow/move_paths/mod.rs1
-rw-r--r--src/librustc_mir/interpret/place.rs59
-rw-r--r--src/librustc_mir/transform/add_retag.rs1
-rw-r--r--src/librustc_mir/transform/check_unsafety.rs50
-rw-r--r--src/librustc_mir/transform/const_prop.rs42
-rw-r--r--src/librustc_mir/transform/inline.rs12
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs119
-rw-r--r--src/librustc_mir/transform/qualify_min_const_fn.rs11
22 files changed, 336 insertions, 283 deletions
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 9f2027e7d05..47b9535abc5 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -1913,9 +1913,6 @@ pub enum PlaceBase<'tcx> {
 
     /// static or static mut variable
     Static(Box<Static<'tcx>>),
-
-    /// Constant code promoted to an injected static
-    Promoted(Box<(Promoted, Ty<'tcx>)>),
 }
 
 /// The `DefId` of a static, along with its normalized type (which is
@@ -1924,11 +1921,13 @@ pub enum PlaceBase<'tcx> {
 pub struct Static<'tcx> {
     pub def_id: DefId,
     pub ty: Ty<'tcx>,
+    pub promoted: Option<Promoted>,
 }
 
 impl_stable_hash_for!(struct Static<'tcx> {
     def_id,
-    ty
+    ty,
+    promoted
 });
 
 /// The `Projection` data structure defines things of the form `B.x`
@@ -2048,7 +2047,7 @@ impl<'tcx> Place<'tcx> {
         match self {
             Place::Base(PlaceBase::Local(local)) => Some(*local),
             Place::Projection(box Projection { base, elem: _ }) => base.base_local(),
-            Place::Base(PlaceBase::Promoted(..)) | Place::Base(PlaceBase::Static(..)) => None,
+            Place::Base(PlaceBase::Static(..)) => None,
         }
     }
 }
@@ -2059,18 +2058,22 @@ impl<'tcx> Debug for Place<'tcx> {
 
         match *self {
             Base(PlaceBase::Local(id)) => write!(fmt, "{:?}", id),
-            Base(PlaceBase::Static(box self::Static { def_id, ty })) => write!(
-                fmt,
-                "({}: {:?})",
-                ty::tls::with(|tcx| tcx.def_path_str(def_id)),
-                ty
-            ),
-            Base(PlaceBase::Promoted(ref promoted)) => write!(
-                fmt,
-                "({:?}: {:?})",
-                promoted.0,
-                promoted.1
-            ),
+            Base(PlaceBase::Static(box self::Static { def_id, ty, promoted })) => {
+                match promoted {
+                    None => write!(
+                        fmt,
+                        "({}: {:?})",
+                        ty::tls::with(|tcx| tcx.def_path_str(def_id)),
+                        ty
+                    ),
+                    Some(pr) => write!(
+                        fmt,
+                        "({:?}: {:?})",
+                        pr,
+                        ty
+                    ),
+                }
+            },
             Projection(ref data) => match data.elem {
                 ProjectionElem::Downcast(ref adt_def, index) => {
                     write!(fmt, "({:?} as {})", data.base, adt_def.variants[index].ident)
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index a6f153eaf64..ac42eacacd7 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -160,7 +160,6 @@ impl<'tcx> Place<'tcx> {
         match *self {
             Place::Base(PlaceBase::Local(index)) =>
                 PlaceTy::Ty { ty: local_decls.local_decls()[index].ty },
-            Place::Base(PlaceBase::Promoted(ref data)) => PlaceTy::Ty { ty: data.1 },
             Place::Base(PlaceBase::Static(ref data)) =>
                 PlaceTy::Ty { ty: data.ty },
             Place::Projection(ref proj) =>
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 8bc0075c477..cddf5782121 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -737,11 +737,18 @@ macro_rules! make_mir_visitor {
                         self.visit_local(local, context, location);
                     }
                     Place::Base(PlaceBase::Static(static_)) => {
+                        match static_.promoted {
+                            None => {
+                                self.visit_static(static_, context, location);
+                            }
+                            Some(_) => {
+                                self.visit_ty(
+                                    & $($mutability)? static_.ty, TyContext::Location(location)
+                                );
+                            }
+                        }
                         self.visit_static(static_, context, location);
                     }
-                    Place::Base(PlaceBase::Promoted(promoted)) => {
-                        self.visit_ty(& $($mutability)? promoted.1, TyContext::Location(location));
-                    },
                     Place::Projection(proj) => {
                         self.visit_projection(proj, context, location);
                     }
@@ -752,7 +759,7 @@ macro_rules! make_mir_visitor {
                             static_: & $($mutability)? Static<'tcx>,
                             _context: PlaceContext<'tcx>,
                             location: Location) {
-                let Static { def_id, ty } = static_;
+                let Static { def_id, ty, promoted: _ } = static_;
                 self.visit_def_id(def_id, location);
                 self.visit_ty(ty, TyContext::Location(location));
             }
diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs
index 14289381aef..8f83c025ceb 100644
--- a/src/librustc_mir/borrow_check/error_reporting.rs
+++ b/src/librustc_mir/borrow_check/error_reporting.rs
@@ -1598,14 +1598,18 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         including_downcast: &IncludingDowncast,
     ) -> Result<(), ()> {
         match *place {
-            Place::Base(PlaceBase::Promoted(_)) => {
-                buf.push_str("promoted");
-            }
             Place::Base(PlaceBase::Local(local)) => {
                 self.append_local_to_string(local, buf)?;
             }
             Place::Base(PlaceBase::Static(ref static_)) => {
-                buf.push_str(&self.infcx.tcx.item_name(static_.def_id).to_string());
+                match static_.promoted {
+                    Some(_) => {
+                        buf.push_str("promoted");
+                    }
+                    None => {
+                        buf.push_str(&self.infcx.tcx.item_name(static_.def_id).to_string());
+                    }
+                }
             }
             Place::Projection(ref proj) => {
                 match proj.elem {
@@ -1744,8 +1748,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                 let local = &self.mir.local_decls[local];
                 self.describe_field_from_ty(&local.ty, field)
             }
-            Place::Base(PlaceBase::Promoted(ref prom)) =>
-                self.describe_field_from_ty(&prom.1, field),
             Place::Base(PlaceBase::Static(ref static_)) =>
                 self.describe_field_from_ty(&static_.ty, field),
             Place::Projection(ref proj) => match proj.elem {
@@ -1828,8 +1830,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         let tcx = self.infcx.tcx;
         match place {
             Place::Base(PlaceBase::Local(_)) |
-            Place::Base(PlaceBase::Static(_)) |
-            Place::Base(PlaceBase::Promoted(_)) => {
+            Place::Base(PlaceBase::Static(_)) => {
                 StorageDeadOrDrop::LocalStorageDead
             }
             Place::Projection(box PlaceProjection { base, elem }) => {
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index c4e371d5afe..5726eba9bda 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -1226,8 +1226,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                                 }
                                 Operand::Move(Place::Base(PlaceBase::Static(..)))
                                 | Operand::Copy(Place::Base(PlaceBase::Static(..)))
-                                | Operand::Move(Place::Base(PlaceBase::Promoted(..)))
-                                | Operand::Copy(Place::Base(PlaceBase::Promoted(..)))
                                 | Operand::Constant(..) => {}
                             }
                         }
@@ -1310,12 +1308,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         //
         // FIXME: allow thread-locals to borrow other thread locals?
         let (might_be_alive, will_be_dropped) = match root_place {
-            Place::Base(PlaceBase::Promoted(_)) => (true, false),
-            Place::Base(PlaceBase::Static(_)) => {
-                // Thread-locals might be dropped after the function exits, but
-                // "true" statics will never be.
-                let is_thread_local = self.is_place_thread_local(&root_place);
-                (true, is_thread_local)
+            Place::Base(PlaceBase::Static(st)) => {
+                match st.promoted {
+                    None => {
+                        // Thread-locals might be dropped after the function exits, but
+                        // "true" statics will never be.
+                        let is_thread_local = self.is_place_thread_local(&root_place);
+                        (true, is_thread_local)
+                    }
+                    Some(_) => (true, false),
+                }
             }
             Place::Base(PlaceBase::Local(_)) => {
                 // Locals are always dropped at function exit, and if they
@@ -1578,7 +1580,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         match *last_prefix {
             Place::Base(PlaceBase::Local(_)) => panic!("should have move path for every Local"),
             Place::Projection(_) => panic!("PrefixSet::All meant don't stop for Projection"),
-            Place::Base(PlaceBase::Promoted(_)) |
             Place::Base(PlaceBase::Static(_)) => Err(NoMovePathFound::ReachedStatic),
         }
     }
@@ -1605,7 +1606,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         let mut place = place;
         loop {
             match *place {
-                Place::Base(PlaceBase::Promoted(_)) |
                 Place::Base(PlaceBase::Local(_)) | Place::Base(PlaceBase::Static(_)) => {
                     // assigning to `x` does not require `x` be initialized.
                     break;
@@ -1954,10 +1954,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                 }
             }
             RootPlace {
-                place: Place::Base(PlaceBase::Promoted(..)),
-                is_local_mutation_allowed: _,
-            } => {}
-            RootPlace {
                 place: Place::Base(PlaceBase::Static(..)),
                 is_local_mutation_allowed: _,
             } => {}
@@ -1994,18 +1990,28 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             }
             // The rules for promotion are made by `qualify_consts`, there wouldn't even be a
             // `Place::Promoted` if the promotion weren't 100% legal. So we just forward this
-            Place::Base(PlaceBase::Promoted(_)) => Ok(RootPlace {
-                place,
-                is_local_mutation_allowed,
-            }),
+//            Place::Base(PlaceBase::Promoted(_)) => Ok(RootPlace {
+//                place,
+//                is_local_mutation_allowed,
+//            }),
             Place::Base(PlaceBase::Static(ref static_)) => {
-                if self.infcx.tcx.is_static(static_.def_id) != Some(hir::Mutability::MutMutable) {
-                    Err(place)
-                } else {
-                    Ok(RootPlace {
-                        place,
-                        is_local_mutation_allowed,
-                    })
+                match static_.promoted {
+                    Some(_) => {
+                        Ok(RootPlace {
+                            place,
+                            is_local_mutation_allowed,
+                        })
+                    }
+                    None => {
+                        if self.infcx.tcx.is_static(static_.def_id) != Some(hir::Mutability::MutMutable) {
+                            Err(place)
+                        } else {
+                            Ok(RootPlace {
+                                place,
+                                is_local_mutation_allowed,
+                            })
+                        }
+                    }
                 }
             }
             Place::Projection(ref proj) => {
diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs
index b8dae98ec64..d8c39e0715a 100644
--- a/src/librustc_mir/borrow_check/mutability_errors.rs
+++ b/src/librustc_mir/borrow_check/mutability_errors.rs
@@ -129,16 +129,19 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
                 }
             }
 
-            Place::Base(PlaceBase::Promoted(_)) => unreachable!(),
-
-            Place::Base(PlaceBase::Static(box Static { def_id, ty: _ })) => {
-                if let Place::Base(PlaceBase::Static(_)) = access_place {
-                    item_msg = format!("immutable static item `{}`", access_place_desc.unwrap());
-                    reason = String::new();
-                } else {
-                    item_msg = format!("`{}`", access_place_desc.unwrap());
-                    let static_name = &self.infcx.tcx.item_name(*def_id);
-                    reason = format!(", as `{}` is an immutable static item", static_name);
+            Place::Base(PlaceBase::Static(box Static { def_id, ty: _, promoted })) => {
+                match promoted {
+                    Some(_) => unreachable!(),
+                    None => {
+                        if let Place::Base(PlaceBase::Static(_)) = access_place {
+                            item_msg = format!("immutable static item `{}`", access_place_desc.unwrap());
+                            reason = String::new();
+                        } else {
+                            item_msg = format!("`{}`", access_place_desc.unwrap());
+                            let static_name = &self.infcx.tcx.item_name(*def_id);
+                            reason = format!(", as `{}` is an immutable static item", static_name);
+                        }
+                    }
                 }
             }
 
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index 25a3160a498..334c20761e7 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -453,51 +453,55 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
             Place::Base(PlaceBase::Local(index)) => PlaceTy::Ty {
                 ty: self.mir.local_decls[index].ty,
             },
-            Place::Base(PlaceBase::Promoted(box (index, sty))) => {
-                let sty = self.sanitize_type(place, sty);
-
-                if !self.errors_reported {
-                    let promoted_mir = &self.mir.promoted[index];
-                    self.sanitize_promoted(promoted_mir, location);
-
-                    let promoted_ty = promoted_mir.return_ty();
-
-                    if let Err(terr) = self.cx.eq_types(
-                        sty,
-                        promoted_ty,
-                        location.to_locations(),
-                        ConstraintCategory::Boring,
-                    ) {
-                        span_mirbug!(
-                            self,
-                            place,
-                            "bad promoted type ({:?}: {:?}): {:?}",
-                            promoted_ty,
-                            sty,
-                            terr
-                        );
-                    };
-                }
-                PlaceTy::Ty { ty: sty }
-            }
-            Place::Base(PlaceBase::Static(box Static { def_id, ty: sty })) => {
-                let sty = self.sanitize_type(place, sty);
-                let ty = self.tcx().type_of(def_id);
-                let ty = self.cx.normalize(ty, location);
-                if let Err(terr) =
-                    self.cx
-                        .eq_types(ty, sty, location.to_locations(), ConstraintCategory::Boring)
-                {
-                    span_mirbug!(
-                        self,
-                        place,
-                        "bad static type ({:?}: {:?}): {:?}",
-                        ty,
-                        sty,
-                        terr
-                    );
+            Place::Base(PlaceBase::Static(box Static { def_id, ty: sty, promoted })) => {
+                match promoted {
+                    Some(pr) => {
+                        let sty = self.sanitize_type(place, sty);
+
+                        if !self.errors_reported {
+                            let promoted_mir = &self.mir.promoted[pr];
+                            self.sanitize_promoted(promoted_mir, location);
+
+                            let promoted_ty = promoted_mir.return_ty();
+
+                            if let Err(terr) = self.cx.eq_types(
+                                sty,
+                                promoted_ty,
+                                location.to_locations(),
+                                ConstraintCategory::Boring,
+                            ) {
+                                span_mirbug!(
+                                    self,
+                                    place,
+                                    "bad promoted type ({:?}: {:?}): {:?}",
+                                    promoted_ty,
+                                    sty,
+                                    terr
+                                );
+                            };
+                        }
+                        PlaceTy::Ty { ty: sty }
+                    }
+                    None => {
+                        let sty = self.sanitize_type(place, sty);
+                        let ty = self.tcx().type_of(def_id);
+                        let ty = self.cx.normalize(ty, location);
+                        if let Err(terr) =
+                            self.cx
+                                .eq_types(ty, sty, location.to_locations(), ConstraintCategory::Boring)
+                        {
+                            span_mirbug!(
+                                self,
+                                place,
+                                "bad static type ({:?}: {:?}): {:?}",
+                                ty,
+                                sty,
+                                terr
+                            );
+                        }
+                        PlaceTy::Ty { ty: sty }
+                    }
                 }
-                PlaceTy::Ty { ty: sty }
             }
             Place::Projection(ref proj) => {
                 let base_context = if context.is_mutating_use() {
diff --git a/src/librustc_mir/borrow_check/path_utils.rs b/src/librustc_mir/borrow_check/path_utils.rs
index 9e0bb93c33a..42eb502b907 100644
--- a/src/librustc_mir/borrow_check/path_utils.rs
+++ b/src/librustc_mir/borrow_check/path_utils.rs
@@ -138,7 +138,6 @@ pub(super) fn is_active<'tcx>(
 /// This is called for all Yield statements on movable generators
 pub(super) fn borrow_of_local_data<'tcx>(place: &Place<'tcx>) -> bool {
     match place {
-        Place::Base(PlaceBase::Promoted(_)) |
         Place::Base(PlaceBase::Static(..)) => false,
         Place::Base(PlaceBase::Local(..)) => true,
         Place::Projection(box proj) => {
diff --git a/src/librustc_mir/borrow_check/place_ext.rs b/src/librustc_mir/borrow_check/place_ext.rs
index c05ee3cf65b..0bbd147d824 100644
--- a/src/librustc_mir/borrow_check/place_ext.rs
+++ b/src/librustc_mir/borrow_check/place_ext.rs
@@ -30,8 +30,6 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
         locals_state_at_exit: &LocalsStateAtExit,
     ) -> bool {
         match self {
-            Place::Base(PlaceBase::Promoted(_)) => false,
-
             // If a local variable is immutable, then we only need to track borrows to guard
             // against two kinds of errors:
             // * The variable being dropped while still borrowed (e.g., because the fn returns
@@ -52,7 +50,12 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
                 }
             }
             Place::Base(PlaceBase::Static(static_)) => {
-                tcx.is_static(static_.def_id) == Some(hir::Mutability::MutMutable)
+                match static_.promoted {
+                    Some(_) => false,
+                    None => {
+                        tcx.is_static(static_.def_id) == Some(hir::Mutability::MutMutable)
+                    }
+                }
             }
             Place::Projection(proj) => match proj.elem {
                 ProjectionElem::Field(..)
@@ -88,7 +91,6 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
         loop {
             match p {
                 Place::Projection(pi) => p = &pi.base,
-                Place::Base(PlaceBase::Promoted(_)) |
                 Place::Base(PlaceBase::Static(_)) => return None,
                 Place::Base(PlaceBase::Local(l)) => return Some(*l),
             }
diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs
index 1d18ada1fb6..7babdfcdd68 100644
--- a/src/librustc_mir/borrow_check/places_conflict.rs
+++ b/src/librustc_mir/borrow_check/places_conflict.rs
@@ -338,7 +338,6 @@ fn unroll_place<'tcx, R>(
             op,
         ),
 
-        Place::Base(PlaceBase::Promoted(_)) |
         Place::Base(PlaceBase::Local(_)) | Place::Base(PlaceBase::Static(_)) => {
             let list = PlaceComponents {
                 component: place,
@@ -371,41 +370,45 @@ fn place_element_conflict<'a, 'gcx: 'tcx, 'tcx>(
                 Overlap::Disjoint
             }
         }
-        (Place::Base(PlaceBase::Static(static1)), Place::Base(PlaceBase::Static(static2))) => {
-            if static1.def_id != static2.def_id {
-                debug!("place_element_conflict: DISJOINT-STATIC");
-                Overlap::Disjoint
-            } else if tcx.is_static(static1.def_id) == Some(hir::Mutability::MutMutable) {
-                // We ignore mutable statics - they can only be unsafe code.
-                debug!("place_element_conflict: IGNORE-STATIC-MUT");
-                Overlap::Disjoint
-            } else {
-                debug!("place_element_conflict: DISJOINT-OR-EQ-STATIC");
-                Overlap::EqualOrDisjoint
-            }
-        }
-        (Place::Base(PlaceBase::Promoted(p1)), Place::Base(PlaceBase::Promoted(p2))) => {
-            if p1.0 == p2.0 {
-                if let ty::Array(_, size) = p1.1.sty {
-                    if size.unwrap_usize(tcx) == 0 {
-                        // Ignore conflicts with promoted [T; 0].
-                        debug!("place_element_conflict: IGNORE-LEN-0-PROMOTED");
-                        return Overlap::Disjoint;
+        (Place::Base(PlaceBase::Static(s1)), Place::Base(PlaceBase::Static(s2))) => {
+            match (s1.promoted, s2.promoted) {
+                (None, None) => {
+                    if s1.def_id != s2.def_id {
+                        debug!("place_element_conflict: DISJOINT-STATIC");
+                        Overlap::Disjoint
+                    } else if tcx.is_static(s1.def_id) == Some(hir::Mutability::MutMutable) {
+                        // We ignore mutable statics - they can only be unsafe code.
+                        debug!("place_element_conflict: IGNORE-STATIC-MUT");
+                        Overlap::Disjoint
+                    } else {
+                        debug!("place_element_conflict: DISJOINT-OR-EQ-STATIC");
+                        Overlap::EqualOrDisjoint
                     }
+                },
+                (Some(p1), Some(p2)) => {
+                    if p1 == p2 {
+                        if let ty::Array(_, size) =s1.ty.sty {
+                            if size.unwrap_usize(tcx) == 0 {
+                                // Ignore conflicts with promoted [T; 0].
+                                debug!("place_element_conflict: IGNORE-LEN-0-PROMOTED");
+                                return Overlap::Disjoint;
+                            }
+                        }
+                        // the same promoted - base case, equal
+                        debug!("place_element_conflict: DISJOINT-OR-EQ-PROMOTED");
+                        Overlap::EqualOrDisjoint
+                    } else {
+                        // different promoteds - base case, disjoint
+                        debug!("place_element_conflict: DISJOINT-PROMOTED");
+                        Overlap::Disjoint
+                    }
+                },
+                (p1_, p2_) => {
+                    debug!("place_element_conflict: DISJOINT-STATIC-LOCAL-PROMOTED");
+                    Overlap::Disjoint
                 }
-                // the same promoted - base case, equal
-                debug!("place_element_conflict: DISJOINT-OR-EQ-PROMOTED");
-                Overlap::EqualOrDisjoint
-            } else {
-                // different promoteds - base case, disjoint
-                debug!("place_element_conflict: DISJOINT-PROMOTED");
-                Overlap::Disjoint
             }
         }
-        (Place::Base(PlaceBase::Local(_)), Place::Base(PlaceBase::Promoted(_))) |
-        (Place::Base(PlaceBase::Promoted(_)), Place::Base(PlaceBase::Local(_))) |
-        (Place::Base(PlaceBase::Promoted(_)), Place::Base(PlaceBase::Static(_))) |
-        (Place::Base(PlaceBase::Static(_)), Place::Base(PlaceBase::Promoted(_))) |
         (Place::Base(PlaceBase::Local(_)), Place::Base(PlaceBase::Static(_))) |
         (Place::Base(PlaceBase::Static(_)), Place::Base(PlaceBase::Local(_))) => {
             debug!("place_element_conflict: DISJOINT-STATIC-LOCAL-PROMOTED");
diff --git a/src/librustc_mir/borrow_check/prefixes.rs b/src/librustc_mir/borrow_check/prefixes.rs
index 384fd5c9987..e70c9e81ebd 100644
--- a/src/librustc_mir/borrow_check/prefixes.rs
+++ b/src/librustc_mir/borrow_check/prefixes.rs
@@ -26,7 +26,6 @@ impl<'tcx> IsPrefixOf<'tcx> for Place<'tcx> {
             }
 
             match *cursor {
-                Place::Base(PlaceBase::Promoted(_)) |
                 Place::Base(PlaceBase::Local(_)) |
                 Place::Base(PlaceBase::Static(_)) => return false,
                 Place::Projection(ref proj) => {
@@ -87,7 +86,6 @@ impl<'cx, 'gcx, 'tcx> Iterator for Prefixes<'cx, 'gcx, 'tcx> {
 
         'cursor: loop {
             let proj = match *cursor {
-                Place::Base(PlaceBase::Promoted(_)) |
                 Place::Base(PlaceBase::Local(_)) | // search yielded this leaf
                 Place::Base(PlaceBase::Static(_)) => {
                     self.next = None;
diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs
index 20b95c363f5..83e1d3ebb3e 100644
--- a/src/librustc_mir/build/expr/as_place.rs
+++ b/src/librustc_mir/build/expr/as_place.rs
@@ -128,6 +128,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             ExprKind::StaticRef { id } => block.and(Place::Base(PlaceBase::Static(Box::new(Static {
                 def_id: id,
                 ty: expr.ty,
+                promoted: None,
             })))),
 
             ExprKind::PlaceTypeAscription { source, user_ty } => {
diff --git a/src/librustc_mir/dataflow/impls/borrowed_locals.rs b/src/librustc_mir/dataflow/impls/borrowed_locals.rs
index b9c8879b3c3..9d4600d13ac 100644
--- a/src/librustc_mir/dataflow/impls/borrowed_locals.rs
+++ b/src/librustc_mir/dataflow/impls/borrowed_locals.rs
@@ -93,7 +93,6 @@ struct BorrowedLocalsVisitor<'b, 'c: 'b> {
 fn find_local<'tcx>(place: &Place<'tcx>) -> Option<Local> {
     match *place {
         Place::Base(PlaceBase::Local(l)) => Some(l),
-        Place::Base(PlaceBase::Promoted(_)) |
         Place::Base(PlaceBase::Static(..)) => None,
         Place::Projection(ref proj) => {
             match proj.elem {
diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs
index 7a9140bce62..71805fd02b8 100644
--- a/src/librustc_mir/dataflow/move_paths/builder.rs
+++ b/src/librustc_mir/dataflow/move_paths/builder.rs
@@ -97,7 +97,6 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
         debug!("lookup({:?})", place);
         match *place {
             Place::Base(PlaceBase::Local(local)) => Ok(self.builder.data.rev_lookup.locals[local]),
-            Place::Base(PlaceBase::Promoted(..)) |
             Place::Base(PlaceBase::Static(..)) => {
                 Err(MoveError::cannot_move_out_of(self.loc, Static))
             }
diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs
index 97f84675f94..7eef68e5f80 100644
--- a/src/librustc_mir/dataflow/move_paths/mod.rs
+++ b/src/librustc_mir/dataflow/move_paths/mod.rs
@@ -286,7 +286,6 @@ impl<'tcx> MovePathLookup<'tcx> {
     pub fn find(&self, place: &Place<'tcx>) -> LookupResult {
         match *place {
             Place::Base(PlaceBase::Local(local)) => LookupResult::Exact(self.locals[local]),
-            Place::Base(PlaceBase::Promoted(_)) |
             Place::Base(PlaceBase::Static(..)) => LookupResult::Parent(None),
             Place::Projection(ref proj) => {
                 match self.find(&proj.base) {
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index 755bbd96b02..62e2cdffadf 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -583,35 +583,38 @@ where
         use rustc::mir::Place::*;
         use rustc::mir::PlaceBase;
         Ok(match *mir_place {
-            Base(PlaceBase::Promoted(ref promoted)) => {
-                let instance = self.frame().instance;
-                self.const_eval_raw(GlobalId {
-                    instance,
-                    promoted: Some(promoted.0),
-                })?
-            }
-
             Base(PlaceBase::Static(ref static_)) => {
-                assert!(!static_.ty.needs_subst());
-                let layout = self.layout_of(static_.ty)?;
-                let instance = ty::Instance::mono(*self.tcx, static_.def_id);
-                let cid = GlobalId {
-                    instance,
-                    promoted: None
-                };
-                // Just create a lazy reference, so we can support recursive statics.
-                // tcx takes are of assigning every static one and only one unique AllocId.
-                // When the data here is ever actually used, memory will notice,
-                // and it knows how to deal with alloc_id that are present in the
-                // global table but not in its local memory: It calls back into tcx through
-                // a query, triggering the CTFE machinery to actually turn this lazy reference
-                // into a bunch of bytes.  IOW, statics are evaluated with CTFE even when
-                // this EvalContext uses another Machine (e.g., in miri).  This is what we
-                // want!  This way, computing statics works concistently between codegen
-                // and miri: They use the same query to eventually obtain a `ty::Const`
-                // and use that for further computation.
-                let alloc = self.tcx.alloc_map.lock().intern_static(cid.instance.def_id());
-                MPlaceTy::from_aligned_ptr(Pointer::from(alloc).with_default_tag(), layout)
+                match static_.promoted {
+                    Some(promoted) => {
+                        let instance = self.frame().instance;
+                        self.const_eval_raw(GlobalId {
+                            instance,
+                            promoted: Some(promoted),
+                        })?
+                    }
+                    None => {
+                        assert!(!static_.ty.needs_subst());
+                        let layout = self.layout_of(static_.ty)?;
+                        let instance = ty::Instance::mono(*self.tcx, static_.def_id);
+                        let cid = GlobalId {
+                            instance,
+                            promoted: None
+                        };
+                        // Just create a lazy reference, so we can support recursive statics.
+                        // tcx takes are of assigning every static one and only one unique AllocId.
+                        // When the data here is ever actually used, memory will notice,
+                        // and it knows how to deal with alloc_id that are present in the
+                        // global table but not in its local memory: It calls back into tcx through
+                        // a query, triggering the CTFE machinery to actually turn this lazy reference
+                        // into a bunch of bytes.  IOW, statics are evaluated with CTFE even when
+                        // this EvalContext uses another Machine (e.g., in miri).  This is what we
+                        // want!  This way, computing statics works concistently between codegen
+                        // and miri: They use the same query to eventually obtain a `ty::Const`
+                        // and use that for further computation.
+                        let alloc = self.tcx.alloc_map.lock().intern_static(cid.instance.def_id());
+                        MPlaceTy::from_aligned_ptr(Pointer::from(alloc).with_default_tag(), layout)
+                    }
+                }
             }
 
             _ => bug!("eval_place_to_mplace called on {:?}", mir_place),
diff --git a/src/librustc_mir/transform/add_retag.rs b/src/librustc_mir/transform/add_retag.rs
index 20b75c55867..b13a5fd2fd1 100644
--- a/src/librustc_mir/transform/add_retag.rs
+++ b/src/librustc_mir/transform/add_retag.rs
@@ -22,7 +22,6 @@ fn is_stable<'tcx>(
     match *place {
         // Locals and statics have stable addresses, for sure
         Base(PlaceBase::Local { .. }) |
-        Base(PlaceBase::Promoted { .. }) |
         Base(PlaceBase::Static { .. }) =>
             true,
         // Recurse for projections
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index b494592c89f..01cb58a481a 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -300,29 +300,33 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
             &Place::Base(PlaceBase::Local(..)) => {
                 // locals are safe
             }
-            &Place::Base(PlaceBase::Promoted(_)) => {
-                bug!("unsafety checking should happen before promotion")
-            }
-            &Place::Base(PlaceBase::Static(box Static { def_id, ty: _ })) => {
-                if self.tcx.is_static(def_id) == Some(hir::Mutability::MutMutable) {
-                    self.require_unsafe("use of mutable static",
-                        "mutable statics can be mutated by multiple threads: aliasing violations \
-                         or data races will cause undefined behavior",
-                         UnsafetyViolationKind::General);
-                } else if self.tcx.is_foreign_item(def_id) {
-                    let source_info = self.source_info;
-                    let lint_root =
-                        self.source_scope_local_data[source_info.scope].lint_root;
-                    self.register_violations(&[UnsafetyViolation {
-                        source_info,
-                        description: Symbol::intern("use of extern static").as_interned_str(),
-                        details:
-                            Symbol::intern("extern statics are not controlled by the Rust type \
-                                            system: invalid data, aliasing violations or data \
-                                            races will cause undefined behavior")
-                                .as_interned_str(),
-                        kind: UnsafetyViolationKind::ExternStatic(lint_root)
-                    }], &[]);
+            &Place::Base(PlaceBase::Static(box Static { def_id, ty: _, promoted })) => {
+                match promoted {
+                    Some(..) => {
+                        bug!("unsafety checking should happen before promotion")
+                    }
+                    None => {
+                        if self.tcx.is_static(def_id) == Some(hir::Mutability::MutMutable) {
+                            self.require_unsafe("use of mutable static",
+                                "mutable statics can be mutated by multiple threads: aliasing violations \
+                                 or data races will cause undefined behavior",
+                                 UnsafetyViolationKind::General);
+                        } else if self.tcx.is_foreign_item(def_id) {
+                            let source_info = self.source_info;
+                            let lint_root =
+                                self.source_scope_local_data[source_info.scope].lint_root;
+                            self.register_violations(&[UnsafetyViolation {
+                                source_info,
+                                description: Symbol::intern("use of extern static").as_interned_str(),
+                                details:
+                                    Symbol::intern("extern statics are not controlled by the Rust type \
+                                                    system: invalid data, aliasing violations or data \
+                                                    races will cause undefined behavior")
+                                        .as_interned_str(),
+                                kind: UnsafetyViolationKind::ExternStatic(lint_root)
+                            }], &[]);
+                        }
+                    }
                 }
             }
         };
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index d8169684420..bbe62fa2d7b 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -282,25 +282,31 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
                 // an `Index` projection would throw us off-track.
                 _ => None,
             },
-            Place::Base(PlaceBase::Promoted(ref promoted)) => {
-                let generics = self.tcx.generics_of(self.source.def_id());
-                if generics.requires_monomorphization(self.tcx) {
-                    // FIXME: can't handle code with generics
-                    return None;
+            Place::Base(PlaceBase::Static(ref static_)) => {
+                match static_.promoted {
+                    Some(promoted) => {
+                        let generics = self.tcx.generics_of(self.source.def_id());
+                        if generics.requires_monomorphization(self.tcx) {
+                            // FIXME: can't handle code with generics
+                            return None;
+                        }
+                        let substs = InternalSubsts::identity_for_item(self.tcx, self.source.def_id());
+                        let instance = Instance::new(self.source.def_id(), substs);
+                        let cid = GlobalId {
+                            instance,
+                            promoted: Some(promoted),
+                        };
+                        // cannot use `const_eval` here, because that would require having the MIR
+                        // for the current function available, but we're producing said MIR right now
+                        let res = self.use_ecx(source_info, |this| {
+                            eval_promoted(this.tcx, cid, this.mir, this.param_env)
+                        })?;
+                        trace!("evaluated promoted {:?} to {:?}", promoted, res);
+                        Some((res.into(), source_info.span))
+                    }
+                    None => None
                 }
-                let substs = InternalSubsts::identity_for_item(self.tcx, self.source.def_id());
-                let instance = Instance::new(self.source.def_id(), substs);
-                let cid = GlobalId {
-                    instance,
-                    promoted: Some(promoted.0),
-                };
-                // cannot use `const_eval` here, because that would require having the MIR
-                // for the current function available, but we're producing said MIR right now
-                let res = self.use_ecx(source_info, |this| {
-                    eval_promoted(this.tcx, cid, this.mir, this.param_env)
-                })?;
-                trace!("evaluated promoted {:?} to {:?}", promoted, res);
-                Some((res.into(), source_info.span))
+
             },
             _ => None,
         }
diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs
index 234483df13a..0b2a34d5fb9 100644
--- a/src/librustc_mir/transform/inline.rs
+++ b/src/librustc_mir/transform/inline.rs
@@ -692,12 +692,16 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
                 // Return pointer; update the place itself
                 *place = self.destination.clone();
             },
-            Place::Base(PlaceBase::Promoted(ref mut promoted)) => {
-                if let Some(p) = self.promoted_map.get(promoted.0).cloned() {
-                    promoted.0 = p;
+            Place::Base(PlaceBase::Static(ref mut static_)) => {
+                match static_.promoted {
+                    Some(promoted) => {
+                        if let Some(p) = self.promoted_map.get(promoted).cloned() {
+                            static_.promoted = Some(p);
+                        }
+                    }
+                    None => self.super_place(place, _ctxt, _location)
                 }
             },
-            _ => self.super_place(place, _ctxt, _location),
         }
     }
 
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index e96689809ad..f0ba1306c99 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -188,8 +188,12 @@ trait Qualif {
     fn in_place(cx: &ConstCx<'_, 'tcx>, place: &Place<'tcx>) -> bool {
         match *place {
             Place::Base(PlaceBase::Local(local)) => Self::in_local(cx, local),
-            Place::Base(PlaceBase::Promoted(_)) => bug!("qualifying already promoted MIR"),
-            Place::Base(PlaceBase::Static(ref static_)) => Self::in_static(cx, static_),
+            Place::Base(PlaceBase::Static(ref static_)) => {
+                match static_.promoted {
+                    Some(..) => bug!("qualifying already promoted MIR"),
+                    None => Self::in_static(cx, static_),
+                 }
+            },
             Place::Projection(ref proj) => Self::in_projection(cx, proj),
         }
     }
@@ -768,17 +772,20 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
                     );
                     dest = &proj.base;
                 },
-                Place::Base(PlaceBase::Promoted(..)) =>
-                    bug!("promoteds don't exist yet during promotion"),
-                Place::Base(PlaceBase::Static(..)) => {
-                    // Catch more errors in the destination. `visit_place` also checks that we
-                    // do not try to access statics from constants or try to mutate statics
-                    self.visit_place(
-                        dest,
-                        PlaceContext::MutatingUse(MutatingUseContext::Store),
-                        location
-                    );
-                    return;
+                Place::Base(PlaceBase::Static(st)) => {
+                    match st.promoted {
+                        Some(..) => bug!("promoteds don't exist yet during promotion"),
+                        None => {
+                            // Catch more errors in the destination. `visit_place` also checks that we
+                            // do not try to access statics from constants or try to mutate statics
+                            self.visit_place(
+                                dest,
+                                PlaceContext::MutatingUse(MutatingUseContext::Store),
+                                location
+                            );
+                            return;
+                        }
+                    }
                 }
             }
         };
@@ -919,51 +926,55 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
         debug!("visit_place: place={:?} context={:?} location={:?}", place, context, location);
         self.super_place(place, context, location);
         match *place {
-            Place::Base(PlaceBase::Local(_)) |
-            Place::Base(PlaceBase::Promoted(_)) => {}
+            Place::Base(PlaceBase::Local(_)) => {}
             Place::Base(PlaceBase::Static(ref global)) => {
-                if self.tcx
-                       .get_attrs(global.def_id)
-                       .iter()
-                       .any(|attr| attr.check_name("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;
-                }
+                match global.promoted {
+                    Some(..) => {}
+                    None => {
+                        if self.tcx
+                               .get_attrs(global.def_id)
+                               .iter()
+                               .any(|attr| attr.check_name("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;
-                }
-                unleash_miri!(self);
+                        // 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;
+                        }
+                        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."
-                        );
+                        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()
+                        }
                     }
-                    err.emit()
                 }
             }
             Place::Projection(ref proj) => {
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index f82e536ab25..ea5bbaeb400 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -256,10 +256,13 @@ fn check_place(
 ) -> McfResult {
     match place {
         Place::Base(PlaceBase::Local(_)) => Ok(()),
-        // promoteds are always fine, they are essentially constants
-        Place::Base(PlaceBase::Promoted(_)) => Ok(()),
-        Place::Base(PlaceBase::Static(_)) =>
-            Err((span, "cannot access `static` items in const fn".into())),
+        Place::Base(PlaceBase::Static(st)) => {
+            match st.promoted {
+                // promoteds are always fine, they are essentially constants
+                Some(..) => Ok(()),
+                None => Err((span, "cannot access `static` items in const fn".into())),
+            }
+        }
         Place::Projection(proj) => {
             match proj.elem {
                 | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. }