about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-07-24 13:10:06 +0000
committerbors <bors@rust-lang.org>2018-07-24 13:10:06 +0000
commit6a3db033ad05f156281d50ee489d727ee0e5d767 (patch)
tree7c93b7fe78be90b0163bfc8e2de40c2220b9c613 /src
parenta1e6bcb2085cba3d5e549ba3b175f99487c21639 (diff)
parentcbd42749efa3555b51463497869af9f829480142 (diff)
downloadrust-6a3db033ad05f156281d50ee489d727ee0e5d767.tar.gz
rust-6a3db033ad05f156281d50ee489d727ee0e5d767.zip
Auto merge of #52597 - oli-obk:promotion_simplify, r=nagisa
Promoteds are statics and statics have a place, not just a value

r? @eddyb

This makes everything around promoteds a little simpler
Diffstat (limited to 'src')
-rw-r--r--src/librustc/ich/impls_mir.rs19
-rw-r--r--src/librustc/mir/mod.rs54
-rw-r--r--src/librustc/mir/tcx.rs1
-rw-r--r--src/librustc/mir/visit.rs22
-rw-r--r--src/librustc_codegen_llvm/consts.rs8
-rw-r--r--src/librustc_codegen_llvm/mir/block.rs28
-rw-r--r--src/librustc_codegen_llvm/mir/constant.rs33
-rw-r--r--src/librustc_codegen_llvm/mir/operand.rs37
-rw-r--r--src/librustc_codegen_llvm/mir/place.rs49
-rw-r--r--src/librustc_mir/borrow_check/error_reporting.rs5
-rw-r--r--src/librustc_mir/borrow_check/mod.rs12
-rw-r--r--src/librustc_mir/borrow_check/move_errors.rs2
-rw-r--r--src/librustc_mir/borrow_check/mutability_errors.rs2
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs100
-rw-r--r--src/librustc_mir/borrow_check/path_utils.rs1
-rw-r--r--src/librustc_mir/borrow_check/place_ext.rs2
-rw-r--r--src/librustc_mir/borrow_check/places_conflict.rs16
-rw-r--r--src/librustc_mir/borrow_check/prefixes.rs2
-rw-r--r--src/librustc_mir/build/expr/as_rvalue.rs19
-rw-r--r--src/librustc_mir/build/matches/mod.rs4
-rw-r--r--src/librustc_mir/build/matches/test.rs12
-rw-r--r--src/librustc_mir/build/misc.rs6
-rw-r--r--src/librustc_mir/dataflow/impls/borrowed_locals.rs1
-rw-r--r--src/librustc_mir/dataflow/impls/borrows.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/hair/cx/expr.rs34
-rw-r--r--src/librustc_mir/hair/cx/mod.rs31
-rw-r--r--src/librustc_mir/hair/mod.rs6
-rw-r--r--src/librustc_mir/interpret/const_eval.rs4
-rw-r--r--src/librustc_mir/interpret/eval_context.rs14
-rw-r--r--src/librustc_mir/interpret/place.rs18
-rw-r--r--src/librustc_mir/shim.rs12
-rw-r--r--src/librustc_mir/transform/add_validation.rs1
-rw-r--r--src/librustc_mir/transform/check_unsafety.rs3
-rw-r--r--src/librustc_mir/transform/const_prop.rs79
-rw-r--r--src/librustc_mir/transform/elaborate_drops.rs4
-rw-r--r--src/librustc_mir/transform/generator.rs16
-rw-r--r--src/librustc_mir/transform/inline.rs27
-rw-r--r--src/librustc_mir/transform/instcombine.rs5
-rw-r--r--src/librustc_mir/transform/promote_consts.rs62
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs9
-rw-r--r--src/librustc_mir/transform/simplify_branches.rs16
-rw-r--r--src/librustc_mir/util/elaborate_drops.rs4
-rw-r--r--src/librustc_passes/mir_stats.rs14
-rw-r--r--src/test/mir-opt/end_region_destruction_extents_1.rs8
-rw-r--r--src/test/mir-opt/match_false_edges.rs6
-rw-r--r--src/test/ui/const-eval/conditional_array_execution.nll.stderr15
-rw-r--r--src/test/ui/const-eval/conditional_array_execution.rs4
-rw-r--r--src/test/ui/const-eval/conditional_array_execution.stderr15
-rw-r--r--src/test/ui/const-eval/issue-43197.nll.stderr30
-rw-r--r--src/test/ui/const-eval/issue-43197.rs6
-rw-r--r--src/test/ui/const-eval/issue-43197.stderr30
-rw-r--r--src/test/ui/const-eval/promoted_const_fn_fail.rs10
-rw-r--r--src/test/ui/const-eval/promoted_const_fn_fail.stderr20
-rw-r--r--src/test/ui/const-eval/promoted_errors.rs2
-rw-r--r--src/test/ui/const-eval/promoted_errors.stderr22
57 files changed, 378 insertions, 587 deletions
diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs
index ed2127cc755..38ea536b4ee 100644
--- a/src/librustc/ich/impls_mir.rs
+++ b/src/librustc/ich/impls_mir.rs
@@ -302,6 +302,9 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::Place<'gcx> {
             mir::Place::Static(ref statik) => {
                 statik.hash_stable(hcx, hasher);
             }
+            mir::Place::Promoted(ref promoted) => {
+                promoted.hash_stable(hcx, hasher);
+            }
             mir::Place::Projection(ref place_projection) => {
                 place_projection.hash_stable(hcx, hasher);
             }
@@ -527,22 +530,6 @@ impl_stable_hash_for!(enum mir::NullOp {
 
 impl_stable_hash_for!(struct mir::Constant<'tcx> { span, ty, literal });
 
-impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::Literal<'gcx> {
-    fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'a>,
-                                          hasher: &mut StableHasher<W>) {
-        mem::discriminant(self).hash_stable(hcx, hasher);
-        match *self {
-            mir::Literal::Value { ref value } => {
-                value.hash_stable(hcx, hasher);
-            }
-            mir::Literal::Promoted { index } => {
-                index.hash_stable(hcx, hasher);
-            }
-        }
-    }
-}
-
 impl_stable_hash_for!(struct mir::Location { block, statement_index });
 
 impl_stable_hash_for!(struct mir::BorrowCheckResult<'tcx> {
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 458c2f3885f..f1f826486a5 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -1701,6 +1701,9 @@ pub enum Place<'tcx> {
     /// static or static mut variable
     Static(Box<Static<'tcx>>),
 
+    /// Constant code promoted to an injected static
+    Promoted(Box<(Promoted, Ty<'tcx>)>),
+
     /// projection out of a place (access a field, deref a pointer, etc)
     Projection(Box<PlaceProjection<'tcx>>),
 }
@@ -1810,6 +1813,7 @@ impl<'tcx> Debug for Place<'tcx> {
                 ty::tls::with(|tcx| tcx.item_path_str(def_id)),
                 ty
             ),
+            Promoted(ref promoted) => write!(fmt, "({:?}: {:?})", promoted.0, promoted.1),
             Projection(ref data) => match data.elem {
                 ProjectionElem::Downcast(ref adt_def, index) => {
                     write!(fmt, "({:?} as {})", data.base, adt_def.variants[index].name)
@@ -1910,9 +1914,7 @@ impl<'tcx> Operand<'tcx> {
         Operand::Constant(box Constant {
             span,
             ty,
-            literal: Literal::Value {
-                value: ty::Const::zero_sized(tcx, ty),
-            },
+            literal: ty::Const::zero_sized(tcx, ty),
         })
     }
 
@@ -2200,38 +2202,15 @@ impl<'tcx> Debug for Rvalue<'tcx> {
 pub struct Constant<'tcx> {
     pub span: Span,
     pub ty: Ty<'tcx>,
-    pub literal: Literal<'tcx>,
+    pub literal: &'tcx ty::Const<'tcx>,
 }
 
 newtype_index!(Promoted { DEBUG_FORMAT = "promoted[{}]" });
 
-#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
-pub enum Literal<'tcx> {
-    Value {
-        value: &'tcx ty::Const<'tcx>,
-    },
-    Promoted {
-        // Index into the `promoted` vector of `Mir`.
-        index: Promoted,
-    },
-}
-
 impl<'tcx> Debug for Constant<'tcx> {
     fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
-        write!(fmt, "{:?}", self.literal)
-    }
-}
-
-impl<'tcx> Debug for Literal<'tcx> {
-    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
-        use self::Literal::*;
-        match *self {
-            Value { value } => {
-                write!(fmt, "const ")?;
-                fmt_const_val(fmt, value)
-            }
-            Promoted { index } => write!(fmt, "{:?}", index),
-        }
+        write!(fmt, "const ")?;
+        fmt_const_val(fmt, self.literal)
     }
 }
 
@@ -2918,20 +2897,3 @@ impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
         self.ty.visit_with(visitor) || self.literal.visit_with(visitor)
     }
 }
-
-impl<'tcx> TypeFoldable<'tcx> for Literal<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        match *self {
-            Literal::Value { value } => Literal::Value {
-                value: value.fold_with(folder),
-            },
-            Literal::Promoted { index } => Literal::Promoted { index },
-        }
-    }
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        match *self {
-            Literal::Value { value } => value.visit_with(visitor),
-            Literal::Promoted { .. } => false,
-        }
-    }
-}
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index 0359eb9b95d..b55843ac527 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -113,6 +113,7 @@ impl<'tcx> Place<'tcx> {
         match *self {
             Place::Local(index) =>
                 PlaceTy::Ty { ty: local_decls.local_decls()[index].ty },
+            Place::Promoted(ref data) => PlaceTy::Ty { ty: data.1 },
             Place::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 758d887cd7b..cab6ed0c122 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -191,12 +191,6 @@ macro_rules! make_mir_visitor {
                 self.super_constant(constant, location);
             }
 
-            fn visit_literal(&mut self,
-                             literal: & $($mutability)* Literal<'tcx>,
-                             location: Location) {
-                self.super_literal(literal, location);
-            }
-
             fn visit_def_id(&mut self,
                             def_id: & $($mutability)* DefId,
                             _: Location) {
@@ -648,6 +642,9 @@ macro_rules! make_mir_visitor {
                     Place::Static(ref $($mutability)* static_) => {
                         self.visit_static(static_, context, location);
                     }
+                    Place::Promoted(ref $($mutability)* promoted) => {
+                        self.visit_ty(& $($mutability)* promoted.1, TyContext::Location(location));
+                    },
                     Place::Projection(ref $($mutability)* proj) => {
                         self.visit_projection(proj, context, location);
                     }
@@ -748,18 +745,7 @@ macro_rules! make_mir_visitor {
 
                 self.visit_span(span);
                 self.visit_ty(ty, TyContext::Location(location));
-                self.visit_literal(literal, location);
-            }
-
-            fn super_literal(&mut self,
-                             literal: & $($mutability)* Literal<'tcx>,
-                             location: Location) {
-                match *literal {
-                    Literal::Value { ref $($mutability)* value } => {
-                        self.visit_const(value, location);
-                    }
-                    Literal::Promoted { index: _ } => {}
-                }
+                self.visit_const(literal, location);
             }
 
             fn super_def_id(&mut self, _def_id: & $($mutability)* DefId) {
diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs
index 5c00947889d..5a2d9580384 100644
--- a/src/librustc_codegen_llvm/consts.rs
+++ b/src/librustc_codegen_llvm/consts.rs
@@ -242,9 +242,11 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef {
     g
 }
 
-pub fn codegen_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
-                                def_id: DefId,
-                                is_mutable: bool) {
+pub fn codegen_static<'a, 'tcx>(
+    cx: &CodegenCx<'a, 'tcx>,
+    def_id: DefId,
+    is_mutable: bool,
+) {
     unsafe {
         let attrs = cx.tcx.codegen_fn_attrs(def_id);
 
diff --git a/src/librustc_codegen_llvm/mir/block.rs b/src/librustc_codegen_llvm/mir/block.rs
index 14d20b6dbe2..dc4b9e0ae99 100644
--- a/src/librustc_codegen_llvm/mir/block.rs
+++ b/src/librustc_codegen_llvm/mir/block.rs
@@ -507,14 +507,40 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
                         // promotes any complex rvalues to constants.
                         if i == 2 && intrinsic.unwrap().starts_with("simd_shuffle") {
                             match *arg {
+                                // The shuffle array argument is usually not an explicit constant,
+                                // but specified directly in the code. This means it gets promoted
+                                // and we can then extract the value by evaluating the promoted.
+                                mir::Operand::Copy(mir::Place::Promoted(box(index, ty))) |
+                                mir::Operand::Move(mir::Place::Promoted(box(index, ty))) => {
+                                    let param_env = ty::ParamEnv::reveal_all();
+                                    let cid = mir::interpret::GlobalId {
+                                        instance: self.instance,
+                                        promoted: Some(index),
+                                    };
+                                    let c = bx.tcx().const_eval(param_env.and(cid));
+                                    let (llval, ty) = self.simd_shuffle_indices(
+                                        &bx,
+                                        terminator.source_info.span,
+                                        ty,
+                                        c,
+                                    );
+                                    return OperandRef {
+                                        val: Immediate(llval),
+                                        layout: bx.cx.layout_of(ty),
+                                    };
+
+                                },
                                 mir::Operand::Copy(_) |
                                 mir::Operand::Move(_) => {
                                     span_bug!(span, "shuffle indices must be constant");
                                 }
                                 mir::Operand::Constant(ref constant) => {
+                                    let c = self.eval_mir_constant(&bx, constant);
                                     let (llval, ty) = self.simd_shuffle_indices(
                                         &bx,
-                                        constant,
+                                        constant.span,
+                                        constant.ty,
+                                        c,
                                     );
                                     return OperandRef {
                                         val: Immediate(llval),
diff --git a/src/librustc_codegen_llvm/mir/constant.rs b/src/librustc_codegen_llvm/mir/constant.rs
index d7939bd2ab2..0d682d5d6f6 100644
--- a/src/librustc_codegen_llvm/mir/constant.rs
+++ b/src/librustc_codegen_llvm/mir/constant.rs
@@ -25,6 +25,7 @@ use consts;
 use type_of::LayoutLlvmExt;
 use type_::Type;
 use syntax::ast::Mutability;
+use syntax::codemap::Span;
 
 use super::super::callee;
 use super::FunctionCx;
@@ -117,13 +118,12 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx, alloc: &Allocation) -> ValueRef {
 
 pub fn codegen_static_initializer<'a, 'tcx>(
     cx: &CodegenCx<'a, 'tcx>,
-    def_id: DefId)
-    -> Result<(ValueRef, &'tcx Allocation), Lrc<ConstEvalErr<'tcx>>>
-{
+    def_id: DefId,
+) -> Result<(ValueRef, &'tcx Allocation), Lrc<ConstEvalErr<'tcx>>> {
     let instance = ty::Instance::mono(cx.tcx, def_id);
     let cid = GlobalId {
         instance,
-        promoted: None
+        promoted: None,
     };
     let param_env = ty::ParamEnv::reveal_all();
     let static_ = cx.tcx.const_eval(param_env.and(cid))?;
@@ -161,28 +161,19 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
         bx: &Builder<'a, 'tcx>,
         constant: &mir::Constant<'tcx>,
     ) -> Result<&'tcx ty::Const<'tcx>, Lrc<ConstEvalErr<'tcx>>> {
-        match constant.literal {
-            mir::Literal::Promoted { index } => {
-                let param_env = ty::ParamEnv::reveal_all();
-                let cid = mir::interpret::GlobalId {
-                    instance: self.instance,
-                    promoted: Some(index),
-                };
-                bx.tcx().const_eval(param_env.and(cid))
-            }
-            mir::Literal::Value { value } => {
-                Ok(self.monomorphize(&value))
-            }
-        }.and_then(|c| self.fully_evaluate(bx, c))
+        let c = self.monomorphize(&constant.literal);
+        self.fully_evaluate(bx, c)
     }
 
     /// process constant containing SIMD shuffle indices
     pub fn simd_shuffle_indices(
         &mut self,
         bx: &Builder<'a, 'tcx>,
-        constant: &mir::Constant<'tcx>,
+        span: Span,
+        ty: Ty<'tcx>,
+        constant: Result<&'tcx ty::Const<'tcx>, Lrc<ConstEvalErr<'tcx>>>,
     ) -> (ValueRef, Ty<'tcx>) {
-        self.eval_mir_constant(bx, constant)
+        constant
             .and_then(|c| {
                 let field_ty = c.ty.builtin_index().unwrap();
                 let fields = match c.ty.sty {
@@ -217,11 +208,11 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
             })
             .unwrap_or_else(|e| {
                 e.report_as_error(
-                    bx.tcx().at(constant.span),
+                    bx.tcx().at(span),
                     "could not evaluate shuffle_indices at compile time",
                 );
                 // We've errored, so we don't have to produce working code.
-                let ty = self.monomorphize(&constant.ty);
+                let ty = self.monomorphize(&ty);
                 let llty = bx.cx.layout_of(ty).llvm_type(bx.cx);
                 (C_undef(llty), ty)
             })
diff --git a/src/librustc_codegen_llvm/mir/operand.rs b/src/librustc_codegen_llvm/mir/operand.rs
index 52234af08c1..777054014dc 100644
--- a/src/librustc_codegen_llvm/mir/operand.rs
+++ b/src/librustc_codegen_llvm/mir/operand.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use llvm::{ValueRef, LLVMConstInBoundsGEP};
+use llvm::ValueRef;
 use rustc::mir::interpret::ConstEvalErr;
 use rustc::mir;
 use rustc::mir::interpret::ConstValue;
@@ -22,14 +22,12 @@ use common::{CodegenCx, C_undef, C_usize};
 use builder::{Builder, MemFlags};
 use value::Value;
 use type_of::LayoutLlvmExt;
-use type_::Type;
-use consts;
 
 use std::fmt;
 use std::ptr;
 
 use super::{FunctionCx, LocalRef};
-use super::constant::{scalar_to_llvm, const_alloc_to_llvm};
+use super::constant::scalar_to_llvm;
 use super::place::PlaceRef;
 
 /// The representation of a Rust value. The enum variant is in fact
@@ -139,16 +137,7 @@ impl<'a, 'tcx> OperandRef<'tcx> {
                 OperandValue::Pair(a_llval, b_llval)
             },
             ConstValue::ByRef(alloc, offset) => {
-                let init = const_alloc_to_llvm(bx.cx, alloc);
-                let base_addr = consts::addr_of(bx.cx, init, layout.align, "byte_str");
-
-                let llval = unsafe { LLVMConstInBoundsGEP(
-                    consts::bitcast(base_addr, Type::i8p(bx.cx)),
-                    &C_usize(bx.cx, offset.bytes()),
-                    1,
-                )};
-                let llval = consts::bitcast(llval, layout.llvm_type(bx.cx).ptr_to());
-                return Ok(PlaceRef::new_sized(llval, layout, alloc.align).load(bx));
+                return Ok(PlaceRef::from_const_alloc(bx, layout, alloc, offset).load(bx));
             },
         };
 
@@ -409,20 +398,12 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
                 self.eval_mir_constant(bx, constant)
                     .and_then(|c| OperandRef::from_const(bx, c))
                     .unwrap_or_else(|err| {
-                        match constant.literal {
-                            mir::Literal::Promoted { .. } => {
-                                // this is unreachable as long as runtime
-                                // and compile-time agree on values
-                                // With floats that won't always be true
-                                // so we generate an abort below
-                            },
-                            mir::Literal::Value { .. } => {
-                                err.report_as_error(
-                                    bx.tcx().at(constant.span),
-                                    "could not evaluate constant operand",
-                                );
-                            },
-                        }
+                        err.report_as_error(
+                            bx.tcx().at(constant.span),
+                            "could not evaluate constant operand",
+                        );
+                        // Allow RalfJ to sleep soundly knowing that even refactorings that remove
+                        // the above error (or silence it under some conditions) will not cause UB
                         let fnname = bx.cx.get_intrinsic(&("llvm.trap"));
                         bx.call(fnname, &[], None);
                         // We've errored, so we don't have to produce working code.
diff --git a/src/librustc_codegen_llvm/mir/place.rs b/src/librustc_codegen_llvm/mir/place.rs
index e7f9457a6a1..9abf9077a95 100644
--- a/src/librustc_codegen_llvm/mir/place.rs
+++ b/src/librustc_codegen_llvm/mir/place.rs
@@ -8,9 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use llvm::{self, ValueRef};
+use llvm::{self, ValueRef, LLVMConstInBoundsGEP};
 use rustc::ty::{self, Ty};
-use rustc::ty::layout::{self, Align, TyLayout, LayoutOf};
+use rustc::ty::layout::{self, Align, TyLayout, LayoutOf, Size};
 use rustc::mir;
 use rustc::mir::tcx::PlaceTy;
 use rustc_data_structures::indexed_vec::Idx;
@@ -22,6 +22,7 @@ use type_of::LayoutLlvmExt;
 use type_::Type;
 use value::Value;
 use glue;
+use mir::constant::const_alloc_to_llvm;
 
 use std::ptr;
 
@@ -56,6 +57,24 @@ impl<'a, 'tcx> PlaceRef<'tcx> {
         }
     }
 
+    pub fn from_const_alloc(
+        bx: &Builder<'a, 'tcx>,
+        layout: TyLayout<'tcx>,
+        alloc: &mir::interpret::Allocation,
+        offset: Size,
+    ) -> PlaceRef<'tcx> {
+        let init = const_alloc_to_llvm(bx.cx, alloc);
+        let base_addr = consts::addr_of(bx.cx, init, layout.align, "byte_str");
+
+        let llval = unsafe { LLVMConstInBoundsGEP(
+            consts::bitcast(base_addr, Type::i8p(bx.cx)),
+            &C_usize(bx.cx, offset.bytes()),
+            1,
+        )};
+        let llval = consts::bitcast(llval, layout.llvm_type(bx.cx).ptr_to());
+        PlaceRef::new_sized(llval, layout, alloc.align)
+    }
+
     pub fn alloca(bx: &Builder<'a, 'tcx>, layout: TyLayout<'tcx>, name: &str)
                   -> PlaceRef<'tcx> {
         debug!("alloca({:?}: {:?})", name, layout);
@@ -421,6 +440,32 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
 
         let result = match *place {
             mir::Place::Local(_) => bug!(), // handled above
+            mir::Place::Promoted(box (index, ty)) => {
+                let param_env = ty::ParamEnv::reveal_all();
+                let cid = mir::interpret::GlobalId {
+                    instance: self.instance,
+                    promoted: Some(index),
+                };
+                let layout = cx.layout_of(self.monomorphize(&ty));
+                match bx.tcx().const_eval(param_env.and(cid)) {
+                    Ok(val) => match val.val {
+                        mir::interpret::ConstValue::ByRef(alloc, offset) => {
+                            PlaceRef::from_const_alloc(bx, layout, alloc, offset)
+                        }
+                        _ => bug!("promoteds should have an allocation: {:?}", val),
+                    },
+                    Err(_) => {
+                        // this is unreachable as long as runtime
+                        // and compile-time agree on values
+                        // With floats that won't always be true
+                        // so we generate an abort
+                        let fnname = bx.cx.get_intrinsic(&("llvm.trap"));
+                        bx.call(fnname, &[], None);
+                        let llval = C_undef(layout.llvm_type(bx.cx).ptr_to());
+                        PlaceRef::new_sized(llval, layout, layout.align)
+                    }
+                }
+            }
             mir::Place::Static(box mir::Static { def_id, ty }) => {
                 let layout = cx.layout_of(self.monomorphize(&ty));
                 PlaceRef::new_sized(consts::get_static(cx, def_id), layout, layout.align)
diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs
index 9e822d28056..9dcee320756 100644
--- a/src/librustc_mir/borrow_check/error_reporting.rs
+++ b/src/librustc_mir/borrow_check/error_reporting.rs
@@ -716,6 +716,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         including_downcast: &IncludingDowncast,
     ) -> Result<(), ()> {
         match *place {
+            Place::Promoted(_) => {
+                buf.push_str("promoted");
+            }
             Place::Local(local) => {
                 self.append_local_to_string(local, buf)?;
             }
@@ -858,6 +861,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                 let local = &self.mir.local_decls[local];
                 self.describe_field_from_ty(&local.ty, field)
             }
+            Place::Promoted(ref prom) => self.describe_field_from_ty(&prom.1, field),
             Place::Static(ref static_) => self.describe_field_from_ty(&static_.ty, field),
             Place::Projection(ref proj) => match proj.elem {
                 ProjectionElem::Deref => self.describe_field(&proj.base, field),
@@ -928,6 +932,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                 let local = &self.mir.local_decls[*local];
                 Some(local.ty)
             }
+            Place::Promoted(ref prom) => Some(prom.1),
             Place::Static(ref st) => Some(st.ty),
             Place::Projection(ref proj) => match proj.elem {
                 ProjectionElem::Field(_, ty) => Some(ty),
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 08500efe8ef..b3d7337cffe 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -1232,6 +1232,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                                 }
                                 Operand::Move(Place::Static(..))
                                 | Operand::Copy(Place::Static(..))
+                                | Operand::Move(Place::Promoted(..))
+                                | Operand::Copy(Place::Promoted(..))
                                 | Operand::Constant(..) => {}
                             }
                         }
@@ -1314,6 +1316,7 @@ 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::Promoted(_) => (true, false),
             Place::Static(statik) => {
                 // Thread-locals might be dropped after the function exits, but
                 // "true" statics will never be.
@@ -1599,6 +1602,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         match *last_prefix {
             Place::Local(_) => panic!("should have move path for every Local"),
             Place::Projection(_) => panic!("PrefixSet::All meant don't stop for Projection"),
+            Place::Promoted(_) |
             Place::Static(_) => return Err(NoMovePathFound::ReachedStatic),
         }
     }
@@ -1625,6 +1629,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         let mut place = place;
         loop {
             match *place {
+                Place::Promoted(_) |
                 Place::Local(_) | Place::Static(_) => {
                     // assigning to `x` does not require `x` be initialized.
                     break;
@@ -1821,6 +1826,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                 }
             }
             RootPlace {
+                place: Place::Promoted(..),
+                is_local_mutation_allowed: _,
+            } => {}
+            RootPlace {
                 place: Place::Static(..),
                 is_local_mutation_allowed: _,
             } => {}
@@ -1855,6 +1864,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                     }),
                 }
             }
+            // promoteds may never be mutated
+            Place::Promoted(_) => bug!("encountered mutable promoted"),
             Place::Static(ref static_) => {
                 if self.tcx.is_static(static_.def_id) != Some(hir::Mutability::MutMutable) {
                     Err(place)
@@ -2021,6 +2032,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         let mut deepest = place;
         loop {
             let proj = match *cursor {
+                Place::Promoted(_) |
                 Place::Local(..) | Place::Static(..) => return deepest,
                 Place::Projection(ref proj) => proj,
             };
diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs
index eacdbe8e945..4aa38fb5f37 100644
--- a/src/librustc_mir/borrow_check/move_errors.rs
+++ b/src/librustc_mir/borrow_check/move_errors.rs
@@ -247,6 +247,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
                                             Place::Projection(ref proj) => {
                                                 proj.base == Place::Local(Local::new(1))
                                             }
+                                            Place::Promoted(_) |
                                             Place::Local(_) | Place::Static(_) => unreachable!(),
                                         }
                                     } =>
@@ -389,6 +390,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
                 // overloaded * operator.
                 local_decl.is_user_variable.is_some() && is_shared_ref(local_decl.ty)
             }
+            Place::Promoted(_) => true,
             Place::Static(ref st) => is_shared_ref(st.ty),
             Place::Projection(ref proj) => match proj.elem {
                 ProjectionElem::Field(_, ty) => is_shared_ref(ty),
diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs
index 760d0a91b79..ab1ff1fa347 100644
--- a/src/librustc_mir/borrow_check/mutability_errors.rs
+++ b/src/librustc_mir/borrow_check/mutability_errors.rs
@@ -122,6 +122,8 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
                 }
             }
 
+            Place::Promoted(_) => unreachable!(),
+
             Place::Static(box Static { def_id, ty: _ }) => {
                 if let Place::Static(_) = access_place {
                     item_msg = format!("immutable static item `{}`", access_place_desc.unwrap());
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 a80cd9ff1a4..b6c8ffcf88d 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -284,69 +284,48 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
             constant, location
         );
 
-        let expected_ty = match constant.literal {
-            Literal::Value { value } => {
-                // FIXME(#46702) -- We need some way to get the predicates
-                // associated with the "pre-evaluated" form of the
-                // constant. For example, consider that the constant
-                // may have associated constant projections (`<Foo as
-                // Trait<'a, 'b>>::SOME_CONST`) that impose
-                // constraints on `'a` and `'b`. These constraints
-                // would be lost if we just look at the normalized
-                // value.
-                if let ty::TyFnDef(def_id, substs) = value.ty.sty {
-                    let tcx = self.tcx();
-                    let type_checker = &mut self.cx;
-
-                    // FIXME -- For now, use the substitutions from
-                    // `value.ty` rather than `value.val`. The
-                    // renumberer will rewrite them to independent
-                    // sets of regions; in principle, we ought to
-                    // derive the type of the `value.val` from "first
-                    // principles" and equate with value.ty, but as we
-                    // are transitioning to the miri-based system, we
-                    // don't have a handy function for that, so for
-                    // now we just ignore `value.val` regions.
-
-                    let instantiated_predicates =
-                        tcx.predicates_of(def_id).instantiate(tcx, substs);
-                    type_checker.normalize_and_prove_instantiated_predicates(
-                        instantiated_predicates,
-                        location.boring(),
-                    );
-                }
-
-                value.ty
-            }
-
-            Literal::Promoted { .. } => {
-                // FIXME -- promoted MIR return types reference
-                // various "free regions" (e.g., scopes and things)
-                // that they ought not to do. We have to figure out
-                // how best to handle that -- probably we want treat
-                // promoted MIR much like closures, renumbering all
-                // their free regions and propagating constraints
-                // upwards. We have the same acyclic guarantees, so
-                // that should be possible. But for now, ignore them.
-                //
-                // let promoted_mir = &self.mir.promoted[index];
-                // promoted_mir.return_ty()
-                return;
-            }
-        };
+        // FIXME(#46702) -- We need some way to get the predicates
+        // associated with the "pre-evaluated" form of the
+        // constant. For example, consider that the constant
+        // may have associated constant projections (`<Foo as
+        // Trait<'a, 'b>>::SOME_CONST`) that impose
+        // constraints on `'a` and `'b`. These constraints
+        // would be lost if we just look at the normalized
+        // value.
+        if let ty::TyFnDef(def_id, substs) = constant.literal.ty.sty {
+            let tcx = self.tcx();
+            let type_checker = &mut self.cx;
+
+            // FIXME -- For now, use the substitutions from
+            // `value.ty` rather than `value.val`. The
+            // renumberer will rewrite them to independent
+            // sets of regions; in principle, we ought to
+            // derive the type of the `value.val` from "first
+            // principles" and equate with value.ty, but as we
+            // are transitioning to the miri-based system, we
+            // don't have a handy function for that, so for
+            // now we just ignore `value.val` regions.
+
+            let instantiated_predicates =
+                tcx.predicates_of(def_id).instantiate(tcx, substs);
+            type_checker.normalize_and_prove_instantiated_predicates(
+                instantiated_predicates,
+                location.boring(),
+            );
+        }
 
-        debug!("sanitize_constant: expected_ty={:?}", expected_ty);
+        debug!("sanitize_constant: expected_ty={:?}", constant.literal.ty);
 
         if let Err(terr) = self
             .cx
-            .eq_types(expected_ty, constant.ty, location.boring())
+            .eq_types(constant.literal.ty, constant.ty, location.boring())
         {
             span_mirbug!(
                 self,
                 constant,
                 "constant {:?} should have type {:?} but has {:?} ({:?})",
                 constant,
-                expected_ty,
+                constant.literal.ty,
                 constant.ty,
                 terr,
             );
@@ -366,6 +345,21 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
             Place::Local(index) => PlaceTy::Ty {
                 ty: self.mir.local_decls[index].ty,
             },
+            Place::Promoted(box (_index, sty)) => {
+                let sty = self.sanitize_type(place, sty);
+                // FIXME -- promoted MIR return types reference
+                // various "free regions" (e.g., scopes and things)
+                // that they ought not to do. We have to figure out
+                // how best to handle that -- probably we want treat
+                // promoted MIR much like closures, renumbering all
+                // their free regions and propagating constraints
+                // upwards. We have the same acyclic guarantees, so
+                // that should be possible. But for now, ignore them.
+                //
+                // let promoted_mir = &self.mir.promoted[index];
+                // promoted_mir.return_ty()
+                PlaceTy::Ty { ty: sty }
+            }
             Place::Static(box Static { def_id, ty: sty }) => {
                 let sty = self.sanitize_type(place, sty);
                 let ty = self.tcx().type_of(def_id);
diff --git a/src/librustc_mir/borrow_check/path_utils.rs b/src/librustc_mir/borrow_check/path_utils.rs
index 499170acee3..70b4e0ea2f0 100644
--- a/src/librustc_mir/borrow_check/path_utils.rs
+++ b/src/librustc_mir/borrow_check/path_utils.rs
@@ -140,6 +140,7 @@ 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::Promoted(_) |
         Place::Static(..) => false,
         Place::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 f6ffe3c6d23..b0517c5e61f 100644
--- a/src/librustc_mir/borrow_check/place_ext.rs
+++ b/src/librustc_mir/borrow_check/place_ext.rs
@@ -26,6 +26,7 @@ crate trait PlaceExt<'tcx> {
 impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
     fn is_unsafe_place(&self, tcx: TyCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>) -> bool {
         match self {
+            Place::Promoted(_) |
             Place::Local(_) => false,
             Place::Static(static_) => {
                 tcx.is_static(static_.def_id) == Some(hir::Mutability::MutMutable)
@@ -52,6 +53,7 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
         loop {
             match p {
                 Place::Projection(pi) => p = &pi.base,
+                Place::Promoted(_) |
                 Place::Static(_) => return None,
                 Place::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 a9eec53fd94..c44af003654 100644
--- a/src/librustc_mir/borrow_check/places_conflict.rs
+++ b/src/librustc_mir/borrow_check/places_conflict.rs
@@ -282,6 +282,7 @@ fn unroll_place<'tcx, R>(
             op,
         ),
 
+        Place::Promoted(_) |
         Place::Local(_) | Place::Static(_) => {
             let list = PlaceComponents {
                 component: place,
@@ -326,8 +327,21 @@ fn place_element_conflict<'a, 'gcx: 'tcx, 'tcx>(
                 Overlap::EqualOrDisjoint
             }
         }
+        (Place::Promoted(p1), Place::Promoted(p2)) => {
+            if p1.0 == p2.0 {
+                // 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::Local(_), Place::Promoted(_)) | (Place::Promoted(_), Place::Local(_)) |
+        (Place::Promoted(_), Place::Static(_)) | (Place::Static(_), Place::Promoted(_)) |
         (Place::Local(_), Place::Static(_)) | (Place::Static(_), Place::Local(_)) => {
-            debug!("place_element_conflict: DISJOINT-STATIC-LOCAL");
+            debug!("place_element_conflict: DISJOINT-STATIC-LOCAL-PROMOTED");
             Overlap::Disjoint
         }
         (Place::Projection(pi1), Place::Projection(pi2)) => {
diff --git a/src/librustc_mir/borrow_check/prefixes.rs b/src/librustc_mir/borrow_check/prefixes.rs
index dee78341265..9b16130d25e 100644
--- a/src/librustc_mir/borrow_check/prefixes.rs
+++ b/src/librustc_mir/borrow_check/prefixes.rs
@@ -36,6 +36,7 @@ impl<'tcx> IsPrefixOf<'tcx> for Place<'tcx> {
             }
 
             match *cursor {
+                Place::Promoted(_) |
                 Place::Local(_) | Place::Static(_) => return false,
                 Place::Projection(ref proj) => {
                     cursor = &proj.base;
@@ -98,6 +99,7 @@ impl<'cx, 'gcx, 'tcx> Iterator for Prefixes<'cx, 'gcx, 'tcx> {
 
         'cursor: loop {
             let proj = match *cursor {
+                Place::Promoted(_) |
                 Place::Local(_) | // search yielded this leaf
                 Place::Static(_) => {
                     self.next = None;
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index 384eb1db04f..68009e962a3 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -239,12 +239,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                         operands.push(Operand::Constant(box Constant {
                             span: expr_span,
                             ty: this.hir.tcx().types.u32,
-                            literal: Literal::Value {
-                                value: ty::Const::from_bits(
-                                    this.hir.tcx(),
-                                    0,
-                                    ty::ParamEnv::empty().and(this.hir.tcx().types.u32)),
-                            },
+                            literal: ty::Const::from_bits(
+                                this.hir.tcx(),
+                                0,
+                                ty::ParamEnv::empty().and(this.hir.tcx().types.u32),
+                            ),
                         }));
                         box AggregateKind::Generator(closure_id, substs, movability)
                     }
@@ -513,9 +512,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         let param_ty = ty::ParamEnv::empty().and(self.hir.tcx().lift_to_global(&ty).unwrap());
         let bits = self.hir.tcx().layout_of(param_ty).unwrap().size.bits();
         let n = (!0u128) >> (128 - bits);
-        let literal = Literal::Value {
-            value: ty::Const::from_bits(self.hir.tcx(), n, param_ty)
-        };
+        let literal = ty::Const::from_bits(self.hir.tcx(), n, param_ty);
 
         self.literal_operand(span, ty, literal)
     }
@@ -526,9 +523,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         let param_ty = ty::ParamEnv::empty().and(self.hir.tcx().lift_to_global(&ty).unwrap());
         let bits = self.hir.tcx().layout_of(param_ty).unwrap().size.bits();
         let n = 1 << (bits - 1);
-        let literal = Literal::Value {
-            value: ty::Const::from_bits(self.hir.tcx(), n, param_ty)
-        };
+        let literal = ty::Const::from_bits(self.hir.tcx(), n, param_ty);
 
         self.literal_operand(span, ty, literal)
     }
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index d75b8d506e7..f1591535fa1 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -505,8 +505,8 @@ enum TestKind<'tcx> {
 
     // test whether the value falls within an inclusive or exclusive range
     Range {
-        lo: Literal<'tcx>,
-        hi: Literal<'tcx>,
+        lo: &'tcx ty::Const<'tcx>,
+        hi: &'tcx ty::Const<'tcx>,
         ty: Ty<'tcx>,
         end: hir::RangeEnd,
     },
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index aa5727ee5c7..e2b460f69fd 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -74,8 +74,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 Test {
                     span: match_pair.pattern.span,
                     kind: TestKind::Range {
-                        lo: Literal::Value { value: lo },
-                        hi: Literal::Value { value: hi },
+                        lo,
+                        hi,
                         ty: match_pair.pattern.ty.clone(),
                         end,
                     },
@@ -260,9 +260,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
             TestKind::Eq { value, mut ty } => {
                 let mut val = Operand::Copy(place.clone());
-                let mut expect = self.literal_operand(test.span, ty, Literal::Value {
-                    value
-                });
+                let mut expect = self.literal_operand(test.span, ty, value);
                 // Use PartialEq::eq instead of BinOp::Eq
                 // (the binop can only handle primitives)
                 let fail = self.cfg.start_new_block();
@@ -300,9 +298,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                                 let array = self.literal_operand(
                                     test.span,
                                     value.ty,
-                                    Literal::Value {
-                                        value
-                                    },
+                                    value,
                                 );
 
                                 let slice = self.temp(ty, test.span);
diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs
index 5907a0cff8e..ae8070698c2 100644
--- a/src/librustc_mir/build/misc.rs
+++ b/src/librustc_mir/build/misc.rs
@@ -35,7 +35,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     pub fn literal_operand(&mut self,
                            span: Span,
                            ty: Ty<'tcx>,
-                           literal: Literal<'tcx>)
+                           literal: &'tcx ty::Const<'tcx>)
                            -> Operand<'tcx> {
         let constant = box Constant {
             span,
@@ -52,9 +52,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     // Returns a zero literal operand for the appropriate type, works for
     // bool, char and integers.
     pub fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
-        let literal = Literal::Value {
-            value: ty::Const::from_bits(self.hir.tcx(), 0, ty::ParamEnv::empty().and(ty))
-        };
+        let literal = ty::Const::from_bits(self.hir.tcx(), 0, ty::ParamEnv::empty().and(ty));
 
         self.literal_operand(span, ty, literal)
     }
diff --git a/src/librustc_mir/dataflow/impls/borrowed_locals.rs b/src/librustc_mir/dataflow/impls/borrowed_locals.rs
index c7513ac8816..96f4c6b60f5 100644
--- a/src/librustc_mir/dataflow/impls/borrowed_locals.rs
+++ b/src/librustc_mir/dataflow/impls/borrowed_locals.rs
@@ -93,6 +93,7 @@ struct BorrowedLocalsVisitor<'b, 'c: 'b> {
 fn find_local<'tcx>(place: &Place<'tcx>) -> Option<Local> {
     match *place {
         Place::Local(l) => Some(l),
+        Place::Promoted(_) |
         Place::Static(..) => None,
         Place::Projection(ref proj) => {
             match proj.elem {
diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs
index 995d1340aca..ea59e42fd47 100644
--- a/src/librustc_mir/dataflow/impls/borrows.rs
+++ b/src/librustc_mir/dataflow/impls/borrows.rs
@@ -259,6 +259,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
                     // Issue #46746: Two-phase borrows handles
                     // stmts of form `Tmp = &mut Borrow` ...
                     match lhs {
+                        Place::Promoted(_) |
                         Place::Local(..) | Place::Static(..) => {} // okay
                         Place::Projection(..) => {
                             // ... can assign into projections,
diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs
index 48236e5fdd1..44e46e90549 100644
--- a/src/librustc_mir/dataflow/move_paths/builder.rs
+++ b/src/librustc_mir/dataflow/move_paths/builder.rs
@@ -108,6 +108,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
         debug!("lookup({:?})", place);
         match *place {
             Place::Local(local) => Ok(self.builder.data.rev_lookup.locals[local]),
+            Place::Promoted(..) |
             Place::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 54609674a47..64bfd36b7ee 100644
--- a/src/librustc_mir/dataflow/move_paths/mod.rs
+++ b/src/librustc_mir/dataflow/move_paths/mod.rs
@@ -249,6 +249,7 @@ impl<'tcx> MovePathLookup<'tcx> {
     pub fn find(&self, place: &Place<'tcx>) -> LookupResult {
         match *place {
             Place::Local(local) => LookupResult::Exact(self.locals[local]),
+            Place::Promoted(_) |
             Place::Static(..) => LookupResult::Parent(None),
             Place::Projection(ref proj) => {
                 match self.find(&proj.base) {
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 13b2a0ab874..b60da286d95 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -627,15 +627,11 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                     None
                 };
                 let source = if let Some((did, offset, ty)) = var {
-                    let mk_const = |val| Expr {
+                    let mk_const = |literal| Expr {
                         temp_lifetime,
                         ty,
                         span: expr.span,
-                        kind: ExprKind::Literal {
-                            literal: Literal::Value {
-                                value: val,
-                            },
-                        },
+                        kind: ExprKind::Literal { literal },
                     }.to_ref();
                     let offset = mk_const(ty::Const::from_bits(
                         cx.tcx,
@@ -706,9 +702,7 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         ty,
         span: expr.span,
         kind: ExprKind::Literal {
-            literal: Literal::Value {
-                value: ty::Const::zero_sized(cx.tcx(), ty),
-            },
+            literal: ty::Const::zero_sized(cx.tcx(), ty),
         },
     }
 }
@@ -760,22 +754,20 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         Def::Method(_) |
         Def::StructCtor(_, CtorKind::Fn) |
         Def::VariantCtor(_, CtorKind::Fn) => ExprKind::Literal {
-            literal: Literal::Value {
-                value: ty::Const::zero_sized(
-                    cx.tcx,
-                    cx.tables().node_id_to_type(expr.hir_id)),
-            },
+            literal: ty::Const::zero_sized(
+                cx.tcx,
+                cx.tables().node_id_to_type(expr.hir_id),
+            ),
         },
 
         Def::Const(def_id) |
         Def::AssociatedConst(def_id) => ExprKind::Literal {
-            literal: Literal::Value {
-                value: ty::Const::unevaluated(
-                    cx.tcx,
-                    def_id,
-                    substs,
-                    cx.tables().node_id_to_type(expr.hir_id))
-            },
+            literal: ty::Const::unevaluated(
+                cx.tcx,
+                def_id,
+                substs,
+                cx.tables().node_id_to_type(expr.hir_id),
+            ),
         },
 
         Def::StructCtor(def_id, CtorKind::Const) |
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index 167e031fbee..4a7225c3a76 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -112,10 +112,8 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
         self.tcx.types.usize
     }
 
-    pub fn usize_literal(&mut self, value: u64) -> Literal<'tcx> {
-        Literal::Value {
-            value: ty::Const::from_usize(self.tcx, value),
-        }
+    pub fn usize_literal(&mut self, value: u64) -> &'tcx ty::Const<'tcx> {
+        ty::Const::from_usize(self.tcx, value)
     }
 
     pub fn bool_ty(&mut self) -> Ty<'tcx> {
@@ -126,16 +124,12 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
         self.tcx.mk_nil()
     }
 
-    pub fn true_literal(&mut self) -> Literal<'tcx> {
-        Literal::Value {
-            value: ty::Const::from_bool(self.tcx, true),
-        }
+    pub fn true_literal(&mut self) -> &'tcx ty::Const<'tcx> {
+        ty::Const::from_bool(self.tcx, true)
     }
 
-    pub fn false_literal(&mut self) -> Literal<'tcx> {
-        Literal::Value {
-            value: ty::Const::from_bool(self.tcx, false),
-        }
+    pub fn false_literal(&mut self) -> &'tcx ty::Const<'tcx> {
+        ty::Const::from_bool(self.tcx, false)
     }
 
     // FIXME: Combine with rustc_mir::hair::pattern::lit_to_const
@@ -145,7 +139,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
         ty: Ty<'tcx>,
         sp: Span,
         neg: bool,
-    ) -> Literal<'tcx> {
+    ) -> &'tcx ty::Const<'tcx> {
         trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg);
 
         let parse_float = |num, fty| -> ConstValue<'tcx> {
@@ -209,9 +203,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
                 defined: 32,
             }),
         };
-        Literal::Value {
-            value: ty::Const::from_const_value(self.tcx, lit, ty)
-        }
+        ty::Const::from_const_value(self.tcx, lit, ty)
     }
 
     pub fn pattern_from_hir(&mut self, p: &hir::Pat) -> Pattern<'tcx> {
@@ -231,17 +223,14 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
                         method_name: &str,
                         self_ty: Ty<'tcx>,
                         params: &[Kind<'tcx>])
-                        -> (Ty<'tcx>, Literal<'tcx>) {
+                        -> (Ty<'tcx>, &'tcx ty::Const<'tcx>) {
         let method_name = Symbol::intern(method_name);
         let substs = self.tcx.mk_substs_trait(self_ty, params);
         for item in self.tcx.associated_items(trait_def_id) {
             if item.kind == ty::AssociatedKind::Method && item.ident.name == method_name {
                 let method_ty = self.tcx.type_of(item.def_id);
                 let method_ty = method_ty.subst(self.tcx, substs);
-                return (method_ty,
-                        Literal::Value {
-                            value: ty::Const::zero_sized(self.tcx, method_ty)
-                        });
+                return (method_ty, ty::Const::zero_sized(self.tcx, method_ty));
             }
         }
 
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index a8d29df8690..c39aa9ca780 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -14,11 +14,11 @@
 //! unit-tested and separated from the Rust source and compiler data
 //! structures.
 
-use rustc::mir::{BinOp, BorrowKind, Field, Literal, UnOp};
+use rustc::mir::{BinOp, BorrowKind, Field, UnOp};
 use rustc::hir::def_id::DefId;
 use rustc::middle::region;
 use rustc::ty::subst::Substs;
-use rustc::ty::{AdtDef, UpvarSubsts, Region, Ty};
+use rustc::ty::{AdtDef, UpvarSubsts, Region, Ty, Const};
 use rustc::hir;
 use syntax::ast;
 use syntax_pos::Span;
@@ -271,7 +271,7 @@ pub enum ExprKind<'tcx> {
         movability: Option<hir::GeneratorMovability>,
     },
     Literal {
-        literal: Literal<'tcx>,
+        literal: &'tcx Const<'tcx>,
     },
     InlineAsm {
         asm: &'tcx hir::InlineAsm,
diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs
index e84132f27cc..3c92f3f6235 100644
--- a/src/librustc_mir/interpret/const_eval.rs
+++ b/src/librustc_mir/interpret/const_eval.rs
@@ -178,7 +178,7 @@ fn eval_body_using_ecx<'a, 'mir, 'tcx>(
     let ptr = ptr.into();
     // always try to read the value and report errors
     let value = match ecx.try_read_value(ptr, layout.align, layout.ty)? {
-        Some(val) if is_static.is_none() => val,
+        Some(val) if is_static.is_none() && cid.promoted.is_none() => val,
         // point at the allocation
         _ => Value::ByRef(ptr, layout.align),
     };
@@ -561,7 +561,7 @@ pub fn const_eval_provider<'a, 'tcx>(
 
     let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env);
     res.and_then(|(mut val, _, miri_ty)| {
-        if tcx.is_static(def_id).is_none() {
+        if tcx.is_static(def_id).is_none() && cid.promoted.is_none() {
             val = ecx.try_read_by_ref(val, miri_ty)?;
         }
         Ok(value_to_const_value(&ecx, val, miri_ty))
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index fac6e8b69ef..10d3af85337 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -831,19 +831,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
             },
 
             Constant(ref constant) => {
-                use rustc::mir::Literal;
-                let mir::Constant { ref literal, .. } = **constant;
-                let value = match *literal {
-                    Literal::Value { ref value } => self.const_to_value(value.val)?,
-
-                    Literal::Promoted { index } => {
-                        let instance = self.frame().instance;
-                        self.read_global_as_value(GlobalId {
-                            instance,
-                            promoted: Some(index),
-                        })?
-                    }
-                };
+                let value = self.const_to_value(constant.literal.val)?;
 
                 Ok(ValTy {
                     value,
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index bb8e5c99d49..28373741c2f 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -109,6 +109,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
             Local(local) => self.frame().get_local(local).map(Some),
             // No fast path for statics. Reading from statics is rare and would require another
             // Machine function to handle differently in miri.
+            Promoted(_) |
             Static(_) => Ok(None),
             Projection(ref proj) => self.try_read_place_projection(proj),
         }
@@ -214,6 +215,23 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 local,
             },
 
+            Promoted(ref promoted) => {
+                let instance = self.frame().instance;
+                let val = self.read_global_as_value(GlobalId {
+                    instance,
+                    promoted: Some(promoted.0),
+                })?;
+                if let Value::ByRef(ptr, align) = val {
+                    Place::Ptr {
+                        ptr,
+                        align,
+                        extra: PlaceExtra::None,
+                    }
+                } else {
+                    bug!("evaluated promoted and got {:#?}", val);
+                }
+            }
+
             Static(ref static_) => {
                 let layout = self.layout_of(self.place_ty(mir_place))?;
                 let instance = ty::Instance::mono(*self.tcx, static_.def_id);
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index c703486560d..7bfbda8b786 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -440,9 +440,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
         let func = Operand::Constant(box Constant {
             span: self.span,
             ty: func_ty,
-            literal: Literal::Value {
-                value: ty::Const::zero_sized(self.tcx, func_ty)
-            },
+            literal: ty::Const::zero_sized(self.tcx, func_ty),
         });
 
         let ref_loc = self.make_place(
@@ -500,9 +498,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
         box Constant {
             span: self.span,
             ty: self.tcx.types.usize,
-            literal: Literal::Value {
-                value: ty::Const::from_usize(self.tcx, value),
-            }
+            literal: ty::Const::from_usize(self.tcx, value),
         }
     }
 
@@ -729,9 +725,7 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             (Operand::Constant(box Constant {
                 span,
                 ty,
-                literal: Literal::Value {
-                    value: ty::Const::zero_sized(tcx, ty)
-                },
+                literal: ty::Const::zero_sized(tcx, ty),
              }),
              vec![rcvr])
         }
diff --git a/src/librustc_mir/transform/add_validation.rs b/src/librustc_mir/transform/add_validation.rs
index 6ffd07915d2..4f7f45f173f 100644
--- a/src/librustc_mir/transform/add_validation.rs
+++ b/src/librustc_mir/transform/add_validation.rs
@@ -34,6 +34,7 @@ fn place_context<'a, 'tcx, D>(
 
     match *place {
         Local { .. } => (None, hir::MutMutable),
+        Promoted(_) |
         Static(_) => (None, hir::MutImmutable),
         Projection(ref proj) => {
             match proj.elem {
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index b4f0a7cd6c4..ab7629eb661 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -222,6 +222,9 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
             &Place::Local(..) => {
                 // locals are safe
             }
+            &Place::Promoted(_) => {
+                bug!("unsafety checking should happen before promotion")
+            }
             &Place::Static(box Static { def_id, ty: _ }) => {
                 if self.tcx.is_static(def_id) == Some(hir::Mutability::MutMutable) {
                     self.require_unsafe("use of mutable static",
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index d15dd14084a..94f96d46996 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -13,7 +13,7 @@
 
 
 use rustc::hir::def::Def;
-use rustc::mir::{Constant, Literal, Location, Place, Mir, Operand, Rvalue, Local};
+use rustc::mir::{Constant, Location, Place, Mir, Operand, Rvalue, Local};
 use rustc::mir::{NullOp, StatementKind, Statement, BasicBlock, LocalKind};
 use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp, ProjectionElem};
 use rustc::mir::visit::{Visitor, PlaceContext};
@@ -174,48 +174,22 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
         c: &Constant<'tcx>,
         source_info: SourceInfo,
     ) -> Option<Const<'tcx>> {
-        match c.literal {
-            Literal::Value { value } => {
-                self.ecx.tcx.span = source_info.span;
-                match self.ecx.const_to_value(value.val) {
-                    Ok(val) => Some((val, value.ty, c.span)),
-                    Err(error) => {
-                        let (stacktrace, span) = self.ecx.generate_stacktrace(None);
-                        let err = ConstEvalErr {
-                            span,
-                            error,
-                            stacktrace,
-                        };
-                        err.report_as_error(
-                            self.tcx.at(source_info.span),
-                            "could not evaluate constant",
-                        );
-                        None
-                    },
-                }
-            },
-            // evaluate the promoted and replace the constant with the evaluated result
-            Literal::Promoted { index } => {
-                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 = Substs::identity_for_item(self.tcx, self.source.def_id);
-                let instance = Instance::new(self.source.def_id, substs);
-                let cid = GlobalId {
-                    instance,
-                    promoted: Some(index),
+        self.ecx.tcx.span = source_info.span;
+        match self.ecx.const_to_value(c.literal.val) {
+            Ok(val) => Some((val, c.literal.ty, c.span)),
+            Err(error) => {
+                let (stacktrace, span) = self.ecx.generate_stacktrace(None);
+                let err = ConstEvalErr {
+                    span,
+                    error,
+                    stacktrace,
                 };
-                // 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 (value, _, ty) = self.use_ecx(source_info, |this| {
-                    eval_promoted(&mut this.ecx, cid, this.mir, this.param_env)
-                })?;
-                let val = (value, ty, c.span);
-                trace!("evaluated {:?} to {:?}", c, val);
-                Some(val)
-            }
+                err.report_as_error(
+                    self.tcx.at(source_info.span),
+                    "could not evaluate constant",
+                );
+                None
+            },
         }
     }
 
@@ -233,6 +207,27 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
                 },
                 _ => None,
             },
+            Place::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;
+                }
+                let substs = Substs::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 (value, _, ty) = self.use_ecx(source_info, |this| {
+                    eval_promoted(&mut this.ecx, cid, this.mir, this.param_env)
+                })?;
+                let val = (value, ty, source_info.span);
+                trace!("evaluated promoted {:?} to {:?}", promoted, val);
+                Some(val)
+            },
             _ => None,
         }
     }
diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs
index 15b0c4a8bf7..d35608068a6 100644
--- a/src/librustc_mir/transform/elaborate_drops.rs
+++ b/src/librustc_mir/transform/elaborate_drops.rs
@@ -530,9 +530,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
         Rvalue::Use(Operand::Constant(Box::new(Constant {
             span,
             ty: self.tcx.types.bool,
-            literal: Literal::Value {
-                value: ty::Const::from_bool(self.tcx, val)
-            }
+            literal: ty::Const::from_bool(self.tcx, val),
         })))
     }
 
diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index a43f17e40df..97467e00385 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -177,12 +177,11 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> {
         let val = Operand::Constant(box Constant {
             span: source_info.span,
             ty: self.tcx.types.u32,
-            literal: Literal::Value {
-                value: ty::Const::from_bits(
-                    self.tcx,
-                    state_disc.into(),
-                    ty::ParamEnv::empty().and(self.tcx.types.u32)),
-            },
+            literal: ty::Const::from_bits(
+                self.tcx,
+                state_disc.into(),
+                ty::ParamEnv::empty().and(self.tcx.types.u32)
+            ),
         });
         Statement {
             source_info,
@@ -337,6 +336,7 @@ struct BorrowedLocals(liveness::LiveVarSet<Local>);
 fn mark_as_borrowed<'tcx>(place: &Place<'tcx>, locals: &mut BorrowedLocals) {
     match *place {
         Place::Local(l) => { locals.0.add(&l); },
+        Place::Promoted(_) |
         Place::Static(..) => (),
         Place::Projection(ref proj) => {
             match proj.elem {
@@ -707,9 +707,7 @@ fn insert_panic_block<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         cond: Operand::Constant(box Constant {
             span: mir.span,
             ty: tcx.types.bool,
-            literal: Literal::Value {
-                value: ty::Const::from_bool(tcx, false),
-            },
+            literal: ty::Const::from_bool(tcx, false),
         }),
         expected: true,
         msg: message,
diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs
index cb57dc572fa..a0a5980d141 100644
--- a/src/librustc_mir/transform/inline.rs
+++ b/src/librustc_mir/transform/inline.rs
@@ -662,11 +662,18 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
                     place: &mut Place<'tcx>,
                     _ctxt: PlaceContext<'tcx>,
                     _location: Location) {
-        if let Place::Local(RETURN_PLACE) = *place {
-            // Return pointer; update the place itself
-            *place = self.destination.clone();
-        } else {
-            self.super_place(place, _ctxt, _location);
+
+        match place {
+            Place::Local(RETURN_PLACE) => {
+                // Return pointer; update the place itself
+                *place = self.destination.clone();
+            },
+            Place::Promoted(ref mut promoted) => {
+                if let Some(p) = self.promoted_map.get(promoted.0).cloned() {
+                    promoted.0 = p;
+                }
+            },
+            _ => self.super_place(place, _ctxt, _location),
         }
     }
 
@@ -749,14 +756,4 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
     fn visit_source_scope(&mut self, scope: &mut SourceScope) {
         *scope = self.scope_map[*scope];
     }
-
-    fn visit_literal(&mut self, literal: &mut Literal<'tcx>, loc: Location) {
-        if let Literal::Promoted { ref mut index } = *literal {
-            if let Some(p) = self.promoted_map.get(*index).cloned() {
-                *index = p;
-            }
-        } else {
-            self.super_literal(literal, loc);
-        }
-    }
 }
diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs
index 8856d263864..6e06beb3041 100644
--- a/src/librustc_mir/transform/instcombine.rs
+++ b/src/librustc_mir/transform/instcombine.rs
@@ -10,7 +10,7 @@
 
 //! Performs various peephole optimizations.
 
-use rustc::mir::{Constant, Literal, Location, Place, Mir, Operand, ProjectionElem, Rvalue, Local};
+use rustc::mir::{Constant, Location, Place, Mir, Operand, ProjectionElem, Rvalue, Local};
 use rustc::mir::visit::{MutVisitor, Visitor};
 use rustc::ty::{TyCtxt, TypeVariants};
 use rustc::util::nodemap::{FxHashMap, FxHashSet};
@@ -103,8 +103,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> {
             if let TypeVariants::TyArray(_, len) = place_ty.sty {
                 let span = self.mir.source_info(location).span;
                 let ty = self.tcx.types.usize;
-                let literal = Literal::Value { value: len };
-                let constant = Constant { span, ty, literal };
+                let constant = Constant { span, ty, literal: len };
                 self.optimizations.arrays_lengths.insert(location, constant);
             }
         }
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index 8dc6539b65d..1d1ef1a151a 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -25,12 +25,12 @@
 use rustc::mir::*;
 use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor};
 use rustc::mir::traversal::ReversePostorder;
-use rustc::ty::{self, TyCtxt};
+use rustc::ty::TyCtxt;
 use syntax_pos::Span;
 
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
 
-use std::{cmp, iter, mem, usize};
+use std::{iter, mem, usize};
 
 /// State of a temporary during collection and promotion.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
@@ -152,7 +152,6 @@ struct Promoter<'a, 'tcx: 'a> {
     source: &'a mut Mir<'tcx>,
     promoted: Mir<'tcx>,
     temps: &'a mut IndexVec<Local, TempState>,
-    extra_statements: &'a mut Vec<(Location, Statement<'tcx>)>,
 
     /// If true, all nested temps are also kept in the
     /// source MIR, not moved to the promoted MIR.
@@ -288,27 +287,21 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
     }
 
     fn promote_candidate(mut self, candidate: Candidate) {
-        let mut rvalue = {
+        let mut operand = {
             let promoted = &mut self.promoted;
-            let literal = Literal::Promoted {
-                index: Promoted::new(self.source.promoted.len())
-            };
-            let operand = |ty, span| {
+            let promoted_id = Promoted::new(self.source.promoted.len());
+            let mut promoted_place = |ty, span| {
                 promoted.span = span;
                 promoted.local_decls[RETURN_PLACE] =
                     LocalDecl::new_return_place(ty, span);
-                Operand::Constant(box Constant {
-                    span,
-                    ty,
-                    literal
-                })
+                Place::Promoted(box (promoted_id, ty))
             };
             let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut();
             match candidate {
                 Candidate::Ref(loc) => {
                     let ref mut statement = blocks[loc.block].statements[loc.statement_index];
                     match statement.kind {
-                        StatementKind::Assign(_, Rvalue::Ref(r, bk, ref mut place)) => {
+                        StatementKind::Assign(_, Rvalue::Ref(_, _, ref mut place)) => {
                             // Find the underlying local for this (necessarilly interior) borrow.
                             // HACK(eddyb) using a recursive function because of mutable borrows.
                             fn interior_base<'a, 'tcx>(place: &'a mut Place<'tcx>)
@@ -322,32 +315,9 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
                             let place = interior_base(place);
 
                             let ty = place.ty(local_decls, self.tcx).to_ty(self.tcx);
-                            let ref_ty = self.tcx.mk_ref(r,
-                                ty::TypeAndMut {
-                                    ty,
-                                    mutbl: bk.to_mutbl_lossy()
-                                }
-                            );
                             let span = statement.source_info.span;
 
-                            // Create a temp to hold the promoted reference.
-                            // This is because `*r` requires `r` to be a local,
-                            // otherwise we would use the `promoted` directly.
-                            let mut promoted_ref = LocalDecl::new_temp(ref_ty, span);
-                            promoted_ref.source_info = statement.source_info;
-                            promoted_ref.visibility_scope = statement.source_info.scope;
-                            let promoted_ref = local_decls.push(promoted_ref);
-                            assert_eq!(self.temps.push(TempState::Unpromotable), promoted_ref);
-                            self.extra_statements.push((loc, Statement {
-                                source_info: statement.source_info,
-                                kind: StatementKind::Assign(
-                                    Place::Local(promoted_ref),
-                                    Rvalue::Use(operand(ref_ty, span)),
-                                )
-                            }));
-                            let promoted_place = Place::Local(promoted_ref).deref();
-
-                            Rvalue::Ref(r, bk, mem::replace(place, promoted_place))
+                            Operand::Move(mem::replace(place, promoted_place(ty, span)))
                         }
                         _ => bug!()
                     }
@@ -358,7 +328,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
                         TerminatorKind::Call { ref mut args, .. } => {
                             let ty = args[index].ty(local_decls, self.tcx);
                             let span = terminator.source_info.span;
-                            Rvalue::Use(mem::replace(&mut args[index], operand(ty, span)))
+                            let operand = Operand::Copy(promoted_place(ty, span));
+                            mem::replace(&mut args[index], operand)
                         }
                         _ => bug!()
                     }
@@ -367,13 +338,13 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
         };
 
         assert_eq!(self.new_block(), START_BLOCK);
-        self.visit_rvalue(&mut rvalue, Location {
+        self.visit_operand(&mut operand, Location {
             block: BasicBlock::new(0),
             statement_index: usize::MAX
         });
 
         let span = self.promoted.span;
-        self.assign(RETURN_PLACE, rvalue, span);
+        self.assign(RETURN_PLACE, Rvalue::Use(operand), span);
         self.source.promoted.push(self.promoted);
     }
 }
@@ -397,7 +368,6 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
     // Visit candidates in reverse, in case they're nested.
     debug!("promote_candidates({:?})", candidates);
 
-    let mut extra_statements = vec![];
     for candidate in candidates.into_iter().rev() {
         match candidate {
             Candidate::Ref(Location { block, statement_index }) => {
@@ -437,19 +407,11 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
             tcx,
             source: mir,
             temps: &mut temps,
-            extra_statements: &mut extra_statements,
             keep_original: false
         };
         promoter.promote_candidate(candidate);
     }
 
-    // Insert each of `extra_statements` before its indicated location, which
-    // has to be done in reverse location order, to not invalidate the rest.
-    extra_statements.sort_by_key(|&(loc, _)| cmp::Reverse(loc));
-    for (loc, statement) in extra_statements {
-        mir[loc.block].statements.insert(loc.statement_index, statement);
-    }
-
     // Eliminate assignments to, and drops of promoted temps.
     let promoted = |index: Local| temps[index] == TempState::PromotedOut;
     for block in mir.basic_blocks_mut() {
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 986957d5a82..4e1129ea7e9 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -449,6 +449,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                     location: Location) {
         match *place {
             Place::Local(ref local) => self.visit_local(local, context, location),
+            Place::Promoted(_) => bug!("promoting already promoted MIR"),
             Place::Static(ref global) => {
                 if self.tcx
                        .get_attrs(global.def_id)
@@ -558,12 +559,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                 }
             }
             Operand::Constant(ref constant) => {
-                if let Literal::Value {
-                    value: &ty::Const { val: ConstValue::Unevaluated(def_id, _), ty, .. }
-                } = constant.literal {
+                if let ConstValue::Unevaluated(def_id, _) = constant.literal.val {
                     // Don't peek inside trait associated constants.
                     if self.tcx.trait_of_item(def_id).is_some() {
-                        self.add_type(ty);
+                        self.add_type(constant.literal.ty);
                     } else {
                         let (bits, _) = self.tcx.at(constant.span).mir_const_qualif(def_id);
 
@@ -573,7 +572,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                         // 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(ty, self.tcx, self.param_env);
+                        self.qualif.restrict(constant.literal.ty, self.tcx, self.param_env);
                     }
                 }
             }
diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs
index 2dbba897fa8..e14941b8aeb 100644
--- a/src/librustc_mir/transform/simplify_branches.rs
+++ b/src/librustc_mir/transform/simplify_branches.rs
@@ -36,11 +36,11 @@ impl MirPass for SimplifyBranches {
         for block in mir.basic_blocks_mut() {
             let terminator = block.terminator_mut();
             terminator.kind = match terminator.kind {
-                TerminatorKind::SwitchInt { discr: Operand::Constant(box Constant {
-                    literal: Literal::Value { ref value }, ..
-                }), switch_ty, ref values, ref targets, .. } => {
+                TerminatorKind::SwitchInt {
+                    discr: Operand::Constant(ref c), switch_ty, ref values, ref targets, ..
+                } => {
                     let switch_ty = ParamEnv::empty().and(switch_ty);
-                    if let Some(constint) = value.assert_bits(tcx, switch_ty) {
+                    if let Some(constint) = c.literal.assert_bits(tcx, switch_ty) {
                         let (otherwise, targets) = targets.split_last().unwrap();
                         let mut ret = TerminatorKind::Goto { target: *otherwise };
                         for (&v, t) in values.iter().zip(targets.iter()) {
@@ -54,11 +54,9 @@ impl MirPass for SimplifyBranches {
                         continue
                     }
                 },
-                TerminatorKind::Assert { target, cond: Operand::Constant(box Constant {
-                    literal: Literal::Value {
-                        value
-                    }, ..
-                }), expected, .. } if (value.assert_bool(tcx) == Some(true)) == expected => {
+                TerminatorKind::Assert {
+                    target, cond: Operand::Constant(ref c), expected, ..
+                } if (c.literal.assert_bool(tcx) == Some(true)) == expected => {
                     TerminatorKind::Goto { target: target }
                 },
                 TerminatorKind::FalseEdges { real_target, .. } => {
diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs
index f70a5ef57fe..689eb62042b 100644
--- a/src/librustc_mir/util/elaborate_drops.rs
+++ b/src/librustc_mir/util/elaborate_drops.rs
@@ -960,9 +960,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
         Operand::Constant(box Constant {
             span: self.source_info.span,
             ty: self.tcx().types.usize,
-            literal: Literal::Value {
-                value: ty::Const::from_usize(self.tcx(), val.into())
-            }
+            literal: ty::Const::from_usize(self.tcx(), val.into()),
         })
     }
 
diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs
index b795685bb6f..3206fa6e172 100644
--- a/src/librustc_passes/mir_stats.rs
+++ b/src/librustc_passes/mir_stats.rs
@@ -13,7 +13,7 @@
 // completely accurate (some things might be counted twice, others missed).
 
 use rustc::mir::{AggregateKind, AssertMessage, BasicBlock, BasicBlockData};
-use rustc::mir::{Constant, Literal, Location, Local, LocalDecl};
+use rustc::mir::{Constant, Location, Local, LocalDecl};
 use rustc::mir::{Place, PlaceElem, PlaceProjection};
 use rustc::mir::{Mir, Operand, ProjectionElem};
 use rustc::mir::{Rvalue, SourceInfo, Statement, StatementKind};
@@ -204,6 +204,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
         self.record(match *place {
             Place::Local(..) => "Place::Local",
             Place::Static(..) => "Place::Static",
+            Place::Promoted(..) => "Place::Promoted",
             Place::Projection(..) => "Place::Projection",
         }, place);
         self.super_place(place, context, location);
@@ -240,17 +241,6 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
         self.super_constant(constant, location);
     }
 
-    fn visit_literal(&mut self,
-                     literal: &Literal<'tcx>,
-                     location: Location) {
-        self.record("Literal", literal);
-        self.record(match *literal {
-            Literal::Value { .. } => "Literal::Value",
-            Literal::Promoted { .. } => "Literal::Promoted",
-        }, literal);
-        self.super_literal(literal, location);
-    }
-
     fn visit_source_info(&mut self,
                          source_info: &SourceInfo) {
         self.record("SourceInfo", source_info);
diff --git a/src/test/mir-opt/end_region_destruction_extents_1.rs b/src/test/mir-opt/end_region_destruction_extents_1.rs
index fab2f9eff5a..8f8c406bcb3 100644
--- a/src/test/mir-opt/end_region_destruction_extents_1.rs
+++ b/src/test/mir-opt/end_region_destruction_extents_1.rs
@@ -122,19 +122,15 @@ unsafe impl<'a, #[may_dangle] 'b> Drop for D1<'a, 'b> {
 //     let mut _6: &'10s S1;
 //     let mut _7: &'10s S1;
 //     let mut _8: S1;
-//     let mut _9: &'10s S1;
-//     let mut _10: &'12ds S1;
 //     bb0: {
 //         StorageLive(_2);
 //         StorageLive(_3);
 //         StorageLive(_4);
-//         _10 = promoted[1];
-//         _4 = &'12ds (*_10);
+//         _4 = &'12ds (promoted[1]: S1);
 //         _3 = &'12ds (*_4);
 //         StorageLive(_6);
 //         StorageLive(_7);
-//         _9 = promoted[0];
-//         _7 = &'10s (*_9);
+//         _7 = &'10s (promoted[0]: S1);
 //         _6 = &'10s (*_7);
 //         _2 = D1<'12ds, '10s>::{{constructor}}(move _3, move _6);
 //         EndRegion('10s);
diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs
index 739cbc0a996..43e711ca902 100644
--- a/src/test/mir-opt/match_false_edges.rs
+++ b/src/test/mir-opt/match_false_edges.rs
@@ -54,8 +54,7 @@ fn main() {
 //      ...
 //      _2 = std::option::Option<i32>::Some(const 42i32,);
 //      _3 = discriminant(_2);
-//      _14 = promoted[1];
-//      _4 = &(*_14);
+//      _4 = &(promoted[1]: std::option::Option<i32>);
 //      _9 = discriminant(_2);
 //      switchInt(move _9) -> [0isize: bb5, 1isize: bb3, otherwise: bb7];
 //  }
@@ -86,8 +85,7 @@ fn main() {
 //  }
 //  bb8: { // binding1 and guard
 //      StorageLive(_7);
-//      _13 = promoted[0];
-//      _7 = &(((*_13) as Some).0: i32);
+//      _7 = &(((promoted[0]: std::option::Option<i32>) as Some).0: i32);
 //      StorageLive(_10);
 //      _10 = const guard() -> [return: bb9, unwind: bb1];
 //  }
diff --git a/src/test/ui/const-eval/conditional_array_execution.nll.stderr b/src/test/ui/const-eval/conditional_array_execution.nll.stderr
index 3f82311d469..86287e12997 100644
--- a/src/test/ui/const-eval/conditional_array_execution.nll.stderr
+++ b/src/test/ui/const-eval/conditional_array_execution.nll.stderr
@@ -12,21 +12,6 @@ note: lint level defined here
 LL | #![warn(const_err)]
    |         ^^^^^^^^^
 
-warning: referenced constant has errors
-  --> $DIR/conditional_array_execution.rs:19:20
-   |
-LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
-   |                   ----- attempt to subtract with overflow
-...
-LL |     println!("{}", FOO);
-   |                    ^^^
-
-warning: this expression will panic at runtime
-  --> $DIR/conditional_array_execution.rs:19:20
-   |
-LL |     println!("{}", FOO);
-   |                    ^^^ referenced constant has errors
-
 error[E0080]: referenced constant has errors
   --> $DIR/conditional_array_execution.rs:19:14
    |
diff --git a/src/test/ui/const-eval/conditional_array_execution.rs b/src/test/ui/const-eval/conditional_array_execution.rs
index 99487eb4979..b3f56f27f63 100644
--- a/src/test/ui/const-eval/conditional_array_execution.rs
+++ b/src/test/ui/const-eval/conditional_array_execution.rs
@@ -17,8 +17,6 @@ const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
 
 fn main() {
     println!("{}", FOO);
-    //~^ WARN this expression will panic at runtime
-    //~| WARN referenced constant
-    //~| ERROR erroneous constant used
+    //~^ ERROR erroneous constant used
     //~| E0080
 }
diff --git a/src/test/ui/const-eval/conditional_array_execution.stderr b/src/test/ui/const-eval/conditional_array_execution.stderr
index 649da03a5e7..29f5f8e2ade 100644
--- a/src/test/ui/const-eval/conditional_array_execution.stderr
+++ b/src/test/ui/const-eval/conditional_array_execution.stderr
@@ -12,21 +12,6 @@ note: lint level defined here
 LL | #![warn(const_err)]
    |         ^^^^^^^^^
 
-warning: referenced constant has errors
-  --> $DIR/conditional_array_execution.rs:19:20
-   |
-LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
-   |                   ----- attempt to subtract with overflow
-...
-LL |     println!("{}", FOO);
-   |                    ^^^
-
-warning: this expression will panic at runtime
-  --> $DIR/conditional_array_execution.rs:19:20
-   |
-LL |     println!("{}", FOO);
-   |                    ^^^ referenced constant has errors
-
 error[E0080]: referenced constant has errors
   --> $DIR/conditional_array_execution.rs:19:20
    |
diff --git a/src/test/ui/const-eval/issue-43197.nll.stderr b/src/test/ui/const-eval/issue-43197.nll.stderr
index e25cb29c114..732fe459834 100644
--- a/src/test/ui/const-eval/issue-43197.nll.stderr
+++ b/src/test/ui/const-eval/issue-43197.nll.stderr
@@ -20,36 +20,6 @@ LL |     const Y: u32 = foo(0-1);
    |                        |
    |                        attempt to subtract with overflow
 
-warning: referenced constant has errors
-  --> $DIR/issue-43197.rs:24:23
-   |
-LL |     const X: u32 = 0-1;
-   |                    --- attempt to subtract with overflow
-...
-LL |     println!("{} {}", X, Y);
-   |                       ^
-
-warning: this expression will panic at runtime
-  --> $DIR/issue-43197.rs:24:23
-   |
-LL |     println!("{} {}", X, Y);
-   |                       ^ referenced constant has errors
-
-warning: referenced constant has errors
-  --> $DIR/issue-43197.rs:24:26
-   |
-LL |     const Y: u32 = foo(0-1);
-   |                        --- attempt to subtract with overflow
-LL |     //~^ WARN this constant cannot be used
-LL |     println!("{} {}", X, Y);
-   |                          ^
-
-warning: this expression will panic at runtime
-  --> $DIR/issue-43197.rs:24:26
-   |
-LL |     println!("{} {}", X, Y);
-   |                          ^ referenced constant has errors
-
 error[E0080]: referenced constant has errors
   --> $DIR/issue-43197.rs:24:14
    |
diff --git a/src/test/ui/const-eval/issue-43197.rs b/src/test/ui/const-eval/issue-43197.rs
index 9304af7b811..c0b45f0ba30 100644
--- a/src/test/ui/const-eval/issue-43197.rs
+++ b/src/test/ui/const-eval/issue-43197.rs
@@ -22,12 +22,8 @@ fn main() {
     const Y: u32 = foo(0-1);
     //~^ WARN this constant cannot be used
     println!("{} {}", X, Y);
-    //~^ WARN this expression will panic at runtime
-    //~| WARN this expression will panic at runtime
-    //~| ERROR erroneous constant used
+    //~^ ERROR erroneous constant used
     //~| ERROR erroneous constant used
     //~| ERROR E0080
     //~| ERROR E0080
-    //~| WARN referenced constant
-    //~| WARN referenced constant
 }
diff --git a/src/test/ui/const-eval/issue-43197.stderr b/src/test/ui/const-eval/issue-43197.stderr
index bf864d81ea3..66921dcd7c5 100644
--- a/src/test/ui/const-eval/issue-43197.stderr
+++ b/src/test/ui/const-eval/issue-43197.stderr
@@ -20,36 +20,6 @@ LL |     const Y: u32 = foo(0-1);
    |                        |
    |                        attempt to subtract with overflow
 
-warning: referenced constant has errors
-  --> $DIR/issue-43197.rs:24:23
-   |
-LL |     const X: u32 = 0-1;
-   |                    --- attempt to subtract with overflow
-...
-LL |     println!("{} {}", X, Y);
-   |                       ^
-
-warning: this expression will panic at runtime
-  --> $DIR/issue-43197.rs:24:23
-   |
-LL |     println!("{} {}", X, Y);
-   |                       ^ referenced constant has errors
-
-warning: referenced constant has errors
-  --> $DIR/issue-43197.rs:24:26
-   |
-LL |     const Y: u32 = foo(0-1);
-   |                        --- attempt to subtract with overflow
-LL |     //~^ WARN this constant cannot be used
-LL |     println!("{} {}", X, Y);
-   |                          ^
-
-warning: this expression will panic at runtime
-  --> $DIR/issue-43197.rs:24:26
-   |
-LL |     println!("{} {}", X, Y);
-   |                          ^ referenced constant has errors
-
 error[E0080]: referenced constant has errors
   --> $DIR/issue-43197.rs:24:26
    |
diff --git a/src/test/ui/const-eval/promoted_const_fn_fail.rs b/src/test/ui/const-eval/promoted_const_fn_fail.rs
index 4888ed6e8dc..f0f35ce614e 100644
--- a/src/test/ui/const-eval/promoted_const_fn_fail.rs
+++ b/src/test/ui/const-eval/promoted_const_fn_fail.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// compile-pass
+
 #![feature(const_fn)]
 
 #![deny(const_err)]
@@ -23,15 +25,13 @@ const fn bar() -> u8 {
         // is run on a system whose pointers need more
         // than 8 bits
         Bar { a: &42 }.b as u8
-        //~^ ERROR this expression will panic at runtime
-        //~| ERROR this expression will panic at runtime
     }
 }
 
 fn main() {
-    // FIXME(oli-obk): this should compile but panic at runtime
-    // if we change the `const_err` lint to allow this will actually compile, but then
-    // continue with undefined values.
+    // FIXME(oli-obk): this should panic at runtime
+    // this will actually compile, but then
+    // abort at runtime (not panic, hard abort).
     let x: &'static u8 = &(bar() + 1);
     let y = *x;
     unreachable!();
diff --git a/src/test/ui/const-eval/promoted_const_fn_fail.stderr b/src/test/ui/const-eval/promoted_const_fn_fail.stderr
deleted file mode 100644
index d805e1a27c9..00000000000
--- a/src/test/ui/const-eval/promoted_const_fn_fail.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-error: this expression will panic at runtime
-  --> $DIR/promoted_const_fn_fail.rs:25:9
-   |
-LL |         Bar { a: &42 }.b as u8
-   |         ^^^^^^^^^^^^^^^^^^^^^^ a raw memory access tried to access part of a pointer value as raw bytes
-   |
-note: lint level defined here
-  --> $DIR/promoted_const_fn_fail.rs:13:9
-   |
-LL | #![deny(const_err)]
-   |         ^^^^^^^^^
-
-error: this expression will panic at runtime
-  --> $DIR/promoted_const_fn_fail.rs:25:9
-   |
-LL |         Bar { a: &42 }.b as u8
-   |         ^^^^^^^^^^^^^^^^^^^^^^ a raw memory access tried to access part of a pointer value as raw bytes
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/const-eval/promoted_errors.rs b/src/test/ui/const-eval/promoted_errors.rs
index 04e9bfbc03e..a58c4be66c4 100644
--- a/src/test/ui/const-eval/promoted_errors.rs
+++ b/src/test/ui/const-eval/promoted_errors.rs
@@ -18,13 +18,11 @@ fn main() {
     //~^ WARN const_err
     println!("{}", 1/(1-1));
     //~^ WARN const_err
-    //~| WARN const_err
     let _x = 1/(1-1);
     //~^ WARN const_err
     //~| WARN const_err
     println!("{}", 1/(false as u32));
     //~^ WARN const_err
-    //~| WARN const_err
     let _x = 1/(false as u32);
     //~^ WARN const_err
     //~| WARN const_err
diff --git a/src/test/ui/const-eval/promoted_errors.stderr b/src/test/ui/const-eval/promoted_errors.stderr
index 9afe5f20af3..85b5696be94 100644
--- a/src/test/ui/const-eval/promoted_errors.stderr
+++ b/src/test/ui/const-eval/promoted_errors.stderr
@@ -16,44 +16,32 @@ warning: attempt to divide by zero
 LL |     println!("{}", 1/(1-1));
    |                    ^^^^^^^
 
-warning: this expression will panic at runtime
-  --> $DIR/promoted_errors.rs:19:20
-   |
-LL |     println!("{}", 1/(1-1));
-   |                    ^^^^^^^ attempt to divide by zero
-
 warning: attempt to divide by zero
-  --> $DIR/promoted_errors.rs:22:14
+  --> $DIR/promoted_errors.rs:21:14
    |
 LL |     let _x = 1/(1-1);
    |              ^^^^^^^
 
 warning: this expression will panic at runtime
-  --> $DIR/promoted_errors.rs:22:14
+  --> $DIR/promoted_errors.rs:21:14
    |
 LL |     let _x = 1/(1-1);
    |              ^^^^^^^ attempt to divide by zero
 
 warning: attempt to divide by zero
-  --> $DIR/promoted_errors.rs:25:20
+  --> $DIR/promoted_errors.rs:24:20
    |
 LL |     println!("{}", 1/(false as u32));
    |                    ^^^^^^^^^^^^^^^^
 
-warning: this expression will panic at runtime
-  --> $DIR/promoted_errors.rs:25:20
-   |
-LL |     println!("{}", 1/(false as u32));
-   |                    ^^^^^^^^^^^^^^^^ attempt to divide by zero
-
 warning: attempt to divide by zero
-  --> $DIR/promoted_errors.rs:28:14
+  --> $DIR/promoted_errors.rs:26:14
    |
 LL |     let _x = 1/(false as u32);
    |              ^^^^^^^^^^^^^^^^
 
 warning: this expression will panic at runtime
-  --> $DIR/promoted_errors.rs:28:14
+  --> $DIR/promoted_errors.rs:26:14
    |
 LL |     let _x = 1/(false as u32);
    |              ^^^^^^^^^^^^^^^^ attempt to divide by zero