about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSantiago Pastorino <spastorino@gmail.com>2019-11-22 17:26:09 -0300
committerOliver Scherer <github35764891676564198441@oli-obk.de>2020-01-10 09:08:24 +0100
commit1688719214ef8a0638e1df543b1a6e77a0909244 (patch)
tree23a78fc91b3a546fb637041cc8b21dbdf1f9959b
parenta59abfa450cf9d18d725c2b757686fd4b65ccbe5 (diff)
downloadrust-1688719214ef8a0638e1df543b1a6e77a0909244.tar.gz
rust-1688719214ef8a0638e1df543b1a6e77a0909244.zip
Promote `Ref`s to constants instead of static
-rw-r--r--src/librustc/mir/interpret/queries.rs7
-rw-r--r--src/librustc/mir/mod.rs11
-rw-r--r--src/librustc/traits/fulfill.rs1
-rw-r--r--src/librustc/traits/select.rs9
-rw-r--r--src/librustc/traits/wf.rs4
-rw-r--r--src/librustc/ty/flags.rs2
-rw-r--r--src/librustc/ty/print/pretty.rs36
-rw-r--r--src/librustc/ty/relate.rs8
-rw-r--r--src/librustc/ty/structural_impls.rs6
-rw-r--r--src/librustc/ty/sty.rs13
-rw-r--r--src/librustc/ty/walk.rs3
-rw-r--r--src/librustc_codegen_ssa/mir/constant.rs9
-rw-r--r--src/librustc_mir/borrow_check/type_check/mod.rs59
-rw-r--r--src/librustc_mir/const_eval.rs2
-rw-r--r--src/librustc_mir/const_eval/eval_queries.rs18
-rw-r--r--src/librustc_mir/hair/cx/expr.rs25
-rw-r--r--src/librustc_mir/hair/pattern/mod.rs1
-rw-r--r--src/librustc_mir/interpret/intern.rs25
-rw-r--r--src/librustc_mir/interpret/operand.rs2
-rw-r--r--src/librustc_mir/monomorphize/collector.rs4
-rw-r--r--src/librustc_mir/transform/check_consts/qualifs.rs4
-rw-r--r--src/librustc_mir/transform/const_prop.rs38
-rw-r--r--src/librustc_mir/transform/promote_consts.rs121
-rw-r--r--src/librustc_typeck/astconv.rs6
-rw-r--r--src/librustdoc/clean/utils.rs8
-rw-r--r--src/test/codegen/consts.rs6
-rw-r--r--src/test/compile-fail/promoted_div_by_zero.rs (renamed from src/test/run-fail/promoted_div_by_zero.rs)2
-rw-r--r--src/test/mir-opt/const_prop/ref_deref.rs6
-rw-r--r--src/test/mir-opt/const_prop/slice_len.rs6
-rw-r--r--src/test/mir-opt/inline/inline-retag.rs10
-rw-r--r--src/test/mir-opt/match_false_edges.rs3
-rw-r--r--src/test/ui/consts/array-literal-index-oob.rs1
-rw-r--r--src/test/ui/consts/array-literal-index-oob.stderr9
-rw-r--r--src/test/ui/consts/const-eval/conditional_array_execution.rs1
-rw-r--r--src/test/ui/consts/const-eval/conditional_array_execution.stderr8
-rw-r--r--src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs2
-rw-r--r--src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr20
-rw-r--r--src/test/ui/consts/const-eval/issue-43197.rs2
-rw-r--r--src/test/ui/consts/const-eval/issue-43197.stderr14
-rw-r--r--src/test/ui/consts/const-eval/issue-44578.rs3
-rw-r--r--src/test/ui/consts/const-eval/issue-44578.stderr8
-rw-r--r--src/test/ui/consts/const-eval/issue-50814.rs6
-rw-r--r--src/test/ui/consts/const-eval/issue-50814.stderr2
-rw-r--r--src/test/ui/consts/const-eval/promoted_errors.rs2
-rw-r--r--src/test/ui/consts/const-eval/promoted_errors.stderr23
-rw-r--r--src/test/ui/consts/const-eval/promoted_errors2.rs2
-rw-r--r--src/test/ui/consts/const-eval/promoted_errors2.stderr23
-rw-r--r--src/test/ui/consts/const-eval/ub-nonnull.stderr2
-rw-r--r--src/test/ui/consts/miri_unleashed/non_const_fn.rs4
-rw-r--r--src/test/ui/consts/miri_unleashed/non_const_fn.stderr8
-rw-r--r--src/test/ui/consts/zst_no_llvm_alloc.rs10
-rw-r--r--src/test/ui/invalid_const_promotion.rs61
-rw-r--r--src/test/ui/symbol-names/impl1.legacy.stderr4
53 files changed, 447 insertions, 223 deletions
diff --git a/src/librustc/mir/interpret/queries.rs b/src/librustc/mir/interpret/queries.rs
index 161c9a3fcc1..2b094bf911f 100644
--- a/src/librustc/mir/interpret/queries.rs
+++ b/src/librustc/mir/interpret/queries.rs
@@ -36,11 +36,16 @@ impl<'tcx> TyCtxt<'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         def_id: DefId,
         substs: SubstsRef<'tcx>,
+        promoted: Option<mir::Promoted>,
         span: Option<Span>,
     ) -> ConstEvalResult<'tcx> {
         let instance = ty::Instance::resolve(self, param_env, def_id, substs);
         if let Some(instance) = instance {
-            self.const_eval_instance(param_env, instance, span)
+            if let Some(promoted) = promoted {
+                self.const_eval_promoted(instance, promoted)
+            } else {
+                self.const_eval_instance(param_env, instance, span)
+            }
         } else {
             Err(ErrorHandled::TooGeneric)
         }
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index ff64302b1e5..0f909dc148f 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -166,6 +166,16 @@ pub struct Body<'tcx> {
 
     /// A span representing this MIR, for error reporting.
     pub span: Span,
+
+    /// The user may be writing e.g. &[(SOME_CELL, 42)][i].1 and this would get promoted, because
+    /// we'd statically know that no thing with interior mutability will ever be available to the
+    /// user without some serious unsafe code.  Now this means that our promoted is actually
+    /// &[(SOME_CELL, 42)] and the MIR using it will do the &promoted[i].1 projection because the
+    /// index may be a runtime value. Such a promoted value is illegal because it has reachable
+    /// interior mutability. This flag just makes this situation very obvious where the previous
+    /// implementation without the flag hid this situation silently.
+    /// FIXME(oli-obk): rewrite the promoted during promotion to eliminate the cell components.
+    pub ignore_interior_mut_in_const_validation: bool,
 }
 
 impl<'tcx> Body<'tcx> {
@@ -202,6 +212,7 @@ impl<'tcx> Body<'tcx> {
             spread_arg: None,
             var_debug_info,
             span,
+            ignore_interior_mut_in_const_validation: false,
             control_flow_destroyed,
         }
     }
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index b0b6994945c..46ece6fc405 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -515,6 +515,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
                             obligation.param_env,
                             def_id,
                             substs,
+                            None,
                             Some(obligation.cause.span),
                         ) {
                             Ok(_) => ProcessResult::Changed(vec![]),
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 1b1cb1b36e0..b7643efdc89 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -802,8 +802,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
             ty::Predicate::ConstEvaluatable(def_id, substs) => {
                 if !(obligation.param_env, substs).has_local_value() {
-                    match self.tcx().const_eval_resolve(obligation.param_env, def_id, substs, None)
-                    {
+                    match self.tcx().const_eval_resolve(
+                        obligation.param_env,
+                        def_id,
+                        substs,
+                        None,
+                        None,
+                    ) {
                         Ok(_) => Ok(EvaluatedToOk),
                         Err(_) => Ok(EvaluatedToErr),
                     }
diff --git a/src/librustc/traits/wf.rs b/src/librustc/traits/wf.rs
index 551f8fde12b..2301395f557 100644
--- a/src/librustc/traits/wf.rs
+++ b/src/librustc/traits/wf.rs
@@ -359,7 +359,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
     /// Pushes the obligations required for an array length to be WF
     /// into `self.out`.
     fn compute_array_len(&mut self, constant: ty::Const<'tcx>) {
-        if let ty::ConstKind::Unevaluated(def_id, substs) = constant.val {
+        if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = constant.val {
+            assert!(promoted.is_none());
+
             let obligations = self.nominal_obligations(def_id, substs);
             self.out.extend(obligations);
 
diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs
index b9aa12b4665..4a4280ba7dc 100644
--- a/src/librustc/ty/flags.rs
+++ b/src/librustc/ty/flags.rs
@@ -219,7 +219,7 @@ impl FlagComputation {
     fn add_const(&mut self, c: &ty::Const<'_>) {
         self.add_ty(c.ty);
         match c.val {
-            ty::ConstKind::Unevaluated(_, substs) => {
+            ty::ConstKind::Unevaluated(_, substs, _) => {
                 self.add_substs(substs);
                 self.add_flags(TypeFlags::HAS_PROJECTION);
             }
diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index 16d89343596..8b1b2bb5865 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -841,23 +841,31 @@ pub trait PrettyPrinter<'tcx>:
 
         match (ct.val, &ct.ty.kind) {
             (_, ty::FnDef(did, substs)) => p!(print_value_path(*did, substs)),
-            (ty::ConstKind::Unevaluated(did, substs), _) => match self.tcx().def_kind(did) {
-                Some(DefKind::Static) | Some(DefKind::Const) | Some(DefKind::AssocConst) => {
-                    p!(print_value_path(did, substs))
-                }
-                _ => {
-                    if did.is_local() {
-                        let span = self.tcx().def_span(did);
-                        if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) {
-                            p!(write("{}", snip))
-                        } else {
-                            p!(write("_: "), print(ct.ty))
+            (ty::ConstKind::Unevaluated(did, substs, promoted), _) => {
+                if let Some(promoted) = promoted {
+                    p!(print_value_path(did, substs));
+                    p!(write("::{:?}", promoted));
+                } else {
+                    match self.tcx().def_kind(did) {
+                        Some(DefKind::Static)
+                        | Some(DefKind::Const)
+                        | Some(DefKind::AssocConst) => p!(print_value_path(did, substs)),
+                        _ => {
+                            if did.is_local() {
+                                let span = self.tcx().def_span(did);
+                                if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span)
+                                {
+                                    p!(write("{}", snip))
+                                } else {
+                                    p!(write("_: "), print(ct.ty))
+                                }
+                            } else {
+                                p!(write("_: "), print(ct.ty))
+                            }
                         }
-                    } else {
-                        p!(write("_: "), print(ct.ty))
                     }
                 }
-            },
+            }
             (ty::ConstKind::Infer(..), _) => p!(write("_: "), print(ct.ty)),
             (ty::ConstKind::Param(ParamConst { name, .. }), _) => p!(write("{}", name)),
             (ty::ConstKind::Value(value), _) => return self.pretty_print_const_value(value, ct.ty),
diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs
index 9472281b56f..3b9df72266f 100644
--- a/src/librustc/ty/relate.rs
+++ b/src/librustc/ty/relate.rs
@@ -568,12 +568,12 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
 
         // FIXME(const_generics): this is wrong, as it is a projection
         (
-            ty::ConstKind::Unevaluated(a_def_id, a_substs),
-            ty::ConstKind::Unevaluated(b_def_id, b_substs),
-        ) if a_def_id == b_def_id => {
+            ty::ConstKind::Unevaluated(a_def_id, a_substs, a_promoted),
+            ty::ConstKind::Unevaluated(b_def_id, b_substs, b_promoted),
+        ) if a_def_id == b_def_id && a_promoted == b_promoted => {
             let substs =
                 relation.relate_with_variance(ty::Variance::Invariant, &a_substs, &b_substs)?;
-            Ok(ty::ConstKind::Unevaluated(a_def_id, &substs))
+            Ok(ty::ConstKind::Unevaluated(a_def_id, &substs, a_promoted))
         }
         _ => Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))),
     };
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 5e24c843025..62e895af7f3 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -1037,8 +1037,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
         match *self {
             ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.fold_with(folder)),
             ty::ConstKind::Param(p) => ty::ConstKind::Param(p.fold_with(folder)),
-            ty::ConstKind::Unevaluated(did, substs) => {
-                ty::ConstKind::Unevaluated(did, substs.fold_with(folder))
+            ty::ConstKind::Unevaluated(did, substs, promoted) => {
+                ty::ConstKind::Unevaluated(did, substs.fold_with(folder), promoted)
             }
             ty::ConstKind::Value(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(..) => {
                 *self
@@ -1050,7 +1050,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
         match *self {
             ty::ConstKind::Infer(ic) => ic.visit_with(visitor),
             ty::ConstKind::Param(p) => p.visit_with(visitor),
-            ty::ConstKind::Unevaluated(_, substs) => substs.visit_with(visitor),
+            ty::ConstKind::Unevaluated(_, substs, _) => substs.visit_with(visitor),
             ty::ConstKind::Value(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => {
                 false
             }
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index c89d045cebb..84236128482 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -9,6 +9,7 @@ use crate::infer::canonical::Canonical;
 use crate::middle::region;
 use crate::mir::interpret::ConstValue;
 use crate::mir::interpret::Scalar;
+use crate::mir::Promoted;
 use crate::ty::layout::VariantIdx;
 use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef};
 use crate::ty::{self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable};
@@ -2375,7 +2376,7 @@ impl<'tcx> Const<'tcx> {
 
     #[inline]
     pub fn eval(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> &Const<'tcx> {
-        let try_const_eval = |did, param_env: ParamEnv<'tcx>, substs| {
+        let try_const_eval = |did, param_env: ParamEnv<'tcx>, substs, promoted| {
             let param_env_and_substs = param_env.with_reveal_all().and(substs);
 
             // Avoid querying `tcx.const_eval(...)` with any e.g. inference vars.
@@ -2387,11 +2388,11 @@ impl<'tcx> Const<'tcx> {
 
             // try to resolve e.g. associated constants to their definition on an impl, and then
             // evaluate the const.
-            tcx.const_eval_resolve(param_env, did, substs, None).ok()
+            tcx.const_eval_resolve(param_env, did, substs, promoted, None).ok()
         };
 
         match self.val {
-            ConstKind::Unevaluated(did, substs) => {
+            ConstKind::Unevaluated(did, substs, promoted) => {
                 // HACK(eddyb) when substs contain e.g. inference variables,
                 // attempt using identity substs instead, that will succeed
                 // when the expression doesn't depend on any parameters.
@@ -2401,12 +2402,12 @@ impl<'tcx> Const<'tcx> {
                     let identity_substs = InternalSubsts::identity_for_item(tcx, did);
                     // The `ParamEnv` needs to match the `identity_substs`.
                     let identity_param_env = tcx.param_env(did);
-                    match try_const_eval(did, identity_param_env, identity_substs) {
+                    match try_const_eval(did, identity_param_env, identity_substs, promoted) {
                         Some(ct) => ct.subst(tcx, substs),
                         None => self,
                     }
                 } else {
-                    try_const_eval(did, param_env, substs).unwrap_or(self)
+                    try_const_eval(did, param_env, substs, promoted).unwrap_or(self)
                 }
             }
             _ => self,
@@ -2470,7 +2471,7 @@ pub enum ConstKind<'tcx> {
 
     /// Used in the HIR by using `Unevaluated` everywhere and later normalizing to one of the other
     /// variants when the code is monomorphic enough for that.
-    Unevaluated(DefId, SubstsRef<'tcx>),
+    Unevaluated(DefId, SubstsRef<'tcx>, Option<Promoted>),
 
     /// Used to hold computed value.
     Value(ConstValue<'tcx>),
diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs
index 9e0dd8e067a..da08fbcf144 100644
--- a/src/librustc/ty/walk.rs
+++ b/src/librustc/ty/walk.rs
@@ -81,7 +81,8 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
         | ty::Bound(..)
         | ty::Foreign(..) => {}
         ty::Array(ty, len) => {
-            if let ty::ConstKind::Unevaluated(_, substs) = len.val {
+            if let ty::ConstKind::Unevaluated(_, substs, promoted) = len.val {
+                assert!(promoted.is_none());
                 stack.extend(substs.types().rev());
             }
             stack.push(len.ty);
diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/src/librustc_codegen_ssa/mir/constant.rs
index f508ed90de4..c6adbc81ce0 100644
--- a/src/librustc_codegen_ssa/mir/constant.rs
+++ b/src/librustc_codegen_ssa/mir/constant.rs
@@ -20,7 +20,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             // use `get_static` to get at their id.
             // FIXME(oli-obk): can we unify this somehow, maybe by making const eval of statics
             // always produce `&STATIC`. This may also simplify how const eval works with statics.
-            ty::ConstKind::Unevaluated(def_id, substs) if self.cx.tcx().is_static(def_id) => {
+            ty::ConstKind::Unevaluated(def_id, substs, promoted)
+                if self.cx.tcx().is_static(def_id) =>
+            {
+                assert!(promoted.is_none());
                 assert!(substs.is_empty(), "we don't support generic statics yet");
                 let static_ = bx.get_static(def_id);
                 // we treat operands referring to statics as if they were `&STATIC` instead
@@ -40,11 +43,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         constant: &mir::Constant<'tcx>,
     ) -> Result<&'tcx ty::Const<'tcx>, ErrorHandled> {
         match constant.literal.val {
-            ty::ConstKind::Unevaluated(def_id, substs) => {
+            ty::ConstKind::Unevaluated(def_id, substs, promoted) => {
                 let substs = self.monomorphize(&substs);
                 self.cx
                     .tcx()
-                    .const_eval_resolve(ty::ParamEnv::reveal_all(), def_id, substs, None)
+                    .const_eval_resolve(ty::ParamEnv::reveal_all(), def_id, substs, promoted, None)
                     .map_err(|err| {
                         self.cx
                             .tcx()
diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs
index b1df198406d..fa6ce3aa4a1 100644
--- a/src/librustc_mir/borrow_check/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/type_check/mod.rs
@@ -310,17 +310,54 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
                 );
             }
         } else {
-            if let ty::ConstKind::Unevaluated(def_id, substs) = constant.literal.val {
-                if let Err(terr) = self.cx.fully_perform_op(
-                    location.to_locations(),
-                    ConstraintCategory::Boring,
-                    self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
-                        constant.literal.ty,
-                        def_id,
-                        UserSubsts { substs, user_self_ty: None },
-                    )),
-                ) {
-                    span_mirbug!(self, constant, "bad constant type {:?} ({:?})", constant, terr);
+            if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = constant.literal.val {
+                if let Some(promoted) = promoted {
+                    let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>,
+                                     promoted: &ReadOnlyBodyAndCache<'_, 'tcx>,
+                                     ty,
+                                     san_ty| {
+                        if let Err(terr) = verifier.cx.eq_types(
+                            san_ty,
+                            ty,
+                            location.to_locations(),
+                            ConstraintCategory::Boring,
+                        ) {
+                            span_mirbug!(
+                                verifier,
+                                promoted,
+                                "bad promoted type ({:?}: {:?}): {:?}",
+                                ty,
+                                san_ty,
+                                terr
+                            );
+                        };
+                    };
+
+                    if !self.errors_reported {
+                        let promoted_body = self.promoted[promoted];
+                        self.sanitize_promoted(promoted_body, location);
+
+                        let promoted_ty = promoted_body.return_ty();
+                        check_err(self, &promoted_body, ty, promoted_ty);
+                    }
+                } else {
+                    if let Err(terr) = self.cx.fully_perform_op(
+                        location.to_locations(),
+                        ConstraintCategory::Boring,
+                        self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
+                            constant.literal.ty,
+                            def_id,
+                            UserSubsts { substs, user_self_ty: None },
+                        )),
+                    ) {
+                        span_mirbug!(
+                            self,
+                            constant,
+                            "bad constant type {:?} ({:?})",
+                            constant,
+                            terr
+                        );
+                    }
                 }
             }
             if let ty::FnDef(def_id, substs) = constant.literal.ty.kind {
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index 7b2ce7f9ac7..eb89553b770 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -52,7 +52,7 @@ pub(crate) fn const_caller_location<'tcx>(
 
     let loc_ty = tcx.caller_location_ty();
     let loc_place = ecx.alloc_caller_location(file, line, col);
-    intern_const_alloc_recursive(&mut ecx, None, loc_place).unwrap();
+    intern_const_alloc_recursive(&mut ecx, None, loc_place, false).unwrap();
     let loc_const = ty::Const {
         ty: loc_ty,
         val: ty::ConstKind::Value(ConstValue::Scalar(loc_place.ptr.into())),
diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs
index 53f3b539bda..d260a6808d1 100644
--- a/src/librustc_mir/const_eval/eval_queries.rs
+++ b/src/librustc_mir/const_eval/eval_queries.rs
@@ -56,7 +56,12 @@ fn eval_body_using_ecx<'mir, 'tcx>(
     ecx.run()?;
 
     // Intern the result
-    intern_const_alloc_recursive(ecx, tcx.static_mutability(cid.instance.def_id()), ret)?;
+    intern_const_alloc_recursive(
+        ecx,
+        tcx.static_mutability(cid.instance.def_id()),
+        ret,
+        body.ignore_interior_mut_in_const_validation,
+    )?;
 
     debug!("eval_body_using_ecx done: {:?}", *ret);
     Ok(ret)
@@ -171,9 +176,14 @@ fn validate_and_turn_into_const<'tcx>(
     let ecx = mk_eval_cx(tcx, tcx.def_span(key.value.instance.def_id()), key.param_env, is_static);
     let val = (|| {
         let mplace = ecx.raw_const_to_mplace(constant)?;
-        let mut ref_tracking = RefTracking::new(mplace);
-        while let Some((mplace, path)) = ref_tracking.todo.pop() {
-            ecx.validate_operand(mplace.into(), path, Some(&mut ref_tracking))?;
+
+        // FIXME do not validate promoteds until a decision on
+        // https://github.com/rust-lang/rust/issues/67465 is made
+        if cid.promoted.is_none() {
+            let mut ref_tracking = RefTracking::new(mplace);
+            while let Some((mplace, path)) = ref_tracking.todo.pop() {
+                ecx.validate_operand(mplace.into(), path, Some(&mut ref_tracking))?;
+            }
         }
         // Now that we validated, turn this into a proper constant.
         // Statics/promoteds are always `ByRef`, for the rest `op_to_const` decides
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 8fd8143ee37..471e09fc03b 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -411,15 +411,18 @@ fn make_mirror_unadjusted<'a, 'tcx>(
             let def_id = cx.tcx.hir().local_def_id(count.hir_id);
             let substs = InternalSubsts::identity_for_item(cx.tcx, def_id);
             let span = cx.tcx.def_span(def_id);
-            let count = match cx.tcx.const_eval_resolve(cx.param_env, def_id, substs, Some(span)) {
-                Ok(cv) => cv.eval_usize(cx.tcx, cx.param_env),
-                Err(ErrorHandled::Reported) => 0,
-                Err(ErrorHandled::TooGeneric) => {
-                    let span = cx.tcx.def_span(def_id);
-                    cx.tcx.sess.span_err(span, "array lengths can't depend on generic parameters");
-                    0
-                }
-            };
+            let count =
+                match cx.tcx.const_eval_resolve(cx.param_env, def_id, substs, None, Some(span)) {
+                    Ok(cv) => cv.eval_usize(cx.tcx, cx.param_env),
+                    Err(ErrorHandled::Reported) => 0,
+                    Err(ErrorHandled::TooGeneric) => {
+                        let span = cx.tcx.def_span(def_id);
+                        cx.tcx
+                            .sess
+                            .span_err(span, "array lengths can't depend on generic parameters");
+                        0
+                    }
+                };
 
             ExprKind::Repeat { value: v.to_ref(), count }
         }
@@ -523,7 +526,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
                             // and not the beginning of discriminants (which is always `0`)
                             let substs = InternalSubsts::identity_for_item(cx.tcx(), did);
                             let lhs = mk_const(cx.tcx().mk_const(ty::Const {
-                                val: ty::ConstKind::Unevaluated(did, substs),
+                                val: ty::ConstKind::Unevaluated(did, substs, None),
                                 ty: var_ty,
                             }));
                             let bin = ExprKind::Binary { op: BinOp::Add, lhs, rhs: offset };
@@ -719,7 +722,7 @@ fn convert_path_expr<'a, 'tcx>(
             debug!("convert_path_expr: (const) user_ty={:?}", user_ty);
             ExprKind::Literal {
                 literal: cx.tcx.mk_const(ty::Const {
-                    val: ty::ConstKind::Unevaluated(def_id, substs),
+                    val: ty::ConstKind::Unevaluated(def_id, substs, None),
                     ty: cx.tables().node_type(expr.hir_id),
                 }),
                 user_ty,
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index 611d3f5b832..73644a4ca3f 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -749,6 +749,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                     self.param_env.with_reveal_all(),
                     def_id,
                     substs,
+                    None,
                     Some(span),
                 ) {
                     Ok(value) => {
diff --git a/src/librustc_mir/interpret/intern.rs b/src/librustc_mir/interpret/intern.rs
index 9b3a2fa36f7..220761ce28d 100644
--- a/src/librustc_mir/interpret/intern.rs
+++ b/src/librustc_mir/interpret/intern.rs
@@ -41,6 +41,11 @@ struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> {
     /// despite the nested mutable reference!
     /// The field gets updated when an `UnsafeCell` is encountered.
     mutability: Mutability,
+
+    /// This flag is to avoid triggering UnsafeCells are not allowed behind references in constants
+    /// for promoteds.
+    /// It's a copy of `mir::Body`'s ignore_interior_mut_in_const_validation field
+    ignore_interior_mut_in_const_validation: bool,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Hash, Eq)]
@@ -164,14 +169,16 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx
                 // References we encounter inside here are interned as pointing to mutable
                 // allocations.
                 let old = std::mem::replace(&mut self.mutability, Mutability::Mut);
-                assert_ne!(
-                    self.mode,
-                    InternMode::Const,
-                    "UnsafeCells are not allowed behind references in constants. This should have \
-                    been prevented statically by const qualification. If this were allowed one \
-                    would be able to change a constant at one use site and other use sites could \
-                    observe that mutation.",
-                );
+                if !self.ignore_interior_mut_in_const_validation {
+                    assert_ne!(
+                        self.mode,
+                        InternMode::Const,
+                        "UnsafeCells are not allowed behind references in constants. This should \
+                        have been prevented statically by const qualification. If this were \
+                        allowed one would be able to change a constant at one use site and other \
+                        use sites could observe that mutation.",
+                    );
+                }
                 let walked = self.walk_aggregate(mplace, fields);
                 self.mutability = old;
                 return walked;
@@ -266,6 +273,7 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
     // The `mutability` of the place, ignoring the type.
     place_mut: Option<hir::Mutability>,
     ret: MPlaceTy<'tcx>,
+    ignore_interior_mut_in_const_validation: bool,
 ) -> InterpResult<'tcx> {
     let tcx = ecx.tcx;
     let (base_mutability, base_intern_mode) = match place_mut {
@@ -302,6 +310,7 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
             mode,
             leftover_allocations,
             mutability,
+            ignore_interior_mut_in_const_validation,
         }
         .visit_value(mplace);
         if let Err(error) = interned {
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index 94a774d646a..ebe600f25da 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -532,7 +532,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // Early-return cases.
         let val_val = match val.val {
             ty::ConstKind::Param(_) => throw_inval!(TooGeneric),
-            ty::ConstKind::Unevaluated(def_id, substs) => {
+            ty::ConstKind::Unevaluated(def_id, substs, promoted) => {
                 let instance = self.resolve(def_id, substs)?;
                 // We use `const_eval` here and `const_eval_raw` elsewhere in mir interpretation.
                 // The reason we use `const_eval_raw` everywhere else is to prevent cycles during
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index 41fbfd22e50..99df9456a6f 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -1249,8 +1249,8 @@ fn collect_const<'tcx>(
                 collect_miri(tcx, id, output);
             }
         }
-        ty::ConstKind::Unevaluated(def_id, substs) => {
-            match tcx.const_eval_resolve(param_env, def_id, substs, None) {
+        ty::ConstKind::Unevaluated(def_id, substs, promoted) => {
+            match tcx.const_eval_resolve(param_env, def_id, substs, promoted, None) {
                 Ok(val) => collect_const(tcx, val, param_substs, output),
                 Err(ErrorHandled::Reported) => {}
                 Err(ErrorHandled::TooGeneric) => {
diff --git a/src/librustc_mir/transform/check_consts/qualifs.rs b/src/librustc_mir/transform/check_consts/qualifs.rs
index 0799cc2374a..253a5899768 100644
--- a/src/librustc_mir/transform/check_consts/qualifs.rs
+++ b/src/librustc_mir/transform/check_consts/qualifs.rs
@@ -102,7 +102,9 @@ pub trait Qualif {
                     // Note: this uses `constant.literal.ty` which is a reference or pointer to the
                     // type of the actual `static` item.
                     Self::in_any_value_of_ty(cx, constant.literal.ty)
-                } else if let ty::ConstKind::Unevaluated(def_id, _) = constant.literal.val {
+                } else if let ty::ConstKind::Unevaluated(def_id, _, promoted) = constant.literal.val
+                {
+                    assert!(promoted.is_none());
                     // Don't peek inside trait associated constants.
                     if cx.tcx.trait_of_item(def_id).is_some() {
                         Self::in_any_value_of_ty(cx, constant.literal.ty)
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index d5d56b36cf4..9614137b7e7 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -17,7 +17,7 @@ use rustc::mir::{
 use rustc::ty::layout::{
     HasDataLayout, HasTyCtxt, LayoutError, LayoutOf, Size, TargetDataLayout, TyLayout,
 };
-use rustc::ty::subst::InternalSubsts;
+use rustc::ty::subst::{InternalSubsts, Subst};
 use rustc::ty::{self, Instance, ParamEnv, Ty, TyCtxt, TypeFoldable};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::DefKind;
@@ -33,7 +33,6 @@ use crate::interpret::{
     LocalState, LocalValue, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Pointer,
     ScalarMaybeUndef, StackPopCleanup,
 };
-use crate::rustc::ty::subst::Subst;
 use crate::transform::{MirPass, MirSource};
 
 /// The maximum number of bytes that we'll allocate space for a return value.
@@ -265,6 +264,7 @@ struct ConstPropagator<'mir, 'tcx> {
     // Because we have `MutVisitor` we can't obtain the `SourceInfo` from a `Location`. So we store
     // the last known `SourceInfo` here and just keep revisiting it.
     source_info: Option<SourceInfo>,
+    lint_root: Option<HirId>,
 }
 
 impl<'mir, 'tcx> LayoutOf for ConstPropagator<'mir, 'tcx> {
@@ -344,6 +344,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             local_decls: body.local_decls.clone(),
             ret: ret.map(Into::into),
             source_info: None,
+            lint_root: None,
         }
     }
 
@@ -377,10 +378,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         F: FnOnce(&mut Self) -> InterpResult<'tcx, T>,
     {
         self.ecx.tcx.span = source_info.span;
-        // FIXME(eddyb) move this to the `Panic(_)` error case, so that
-        // `f(self)` is always called, and that the only difference when the
-        // scope's `local_data` is missing, is that the lint isn't emitted.
-        let lint_root = self.lint_root(source_info)?;
         let r = match f(self) {
             Ok(val) => Some(val),
             Err(error) => {
@@ -414,7 +411,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                         diagnostic.report_as_lint(
                             self.ecx.tcx,
                             "this expression will panic at runtime",
-                            lint_root,
+                            self.lint_root?,
                             None,
                         );
                     }
@@ -426,17 +423,19 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         r
     }
 
-    fn eval_constant(
-        &mut self,
-        c: &Constant<'tcx>,
-        source_info: SourceInfo,
-    ) -> Option<Const<'tcx>> {
+    fn eval_constant(&mut self, c: &Constant<'tcx>) -> Option<Const<'tcx>> {
         self.ecx.tcx.span = c.span;
+
+        // FIXME we need to revisit this for #67176
+        if c.needs_subst() {
+            return None;
+        }
+
         match self.ecx.eval_const_to_op(c.literal, None) {
             Ok(op) => Some(op),
             Err(error) => {
                 let err = error_to_const_error(&self.ecx, error);
-                match self.lint_root(source_info) {
+                match self.lint_root {
                     Some(lint_root) if c.literal.needs_subst() => {
                         // Out of backwards compatibility we cannot report hard errors in unused
                         // generic functions using associated constants of the generic parameters.
@@ -463,7 +462,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
 
     fn eval_operand(&mut self, op: &Operand<'tcx>, source_info: SourceInfo) -> Option<Const<'tcx>> {
         match *op {
-            Operand::Constant(ref c) => self.eval_constant(c, source_info),
+            Operand::Constant(ref c) => self.eval_constant(c),
             Operand::Move(ref place) | Operand::Copy(ref place) => {
                 self.eval_place(place, source_info)
             }
@@ -552,6 +551,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             return None;
         }
 
+        // FIXME we need to revisit this for #67176
+        if rvalue.needs_subst() {
+            return None;
+        }
+
         let overflow_check = self.tcx.sess.overflow_checks();
 
         // Perform any special handling for specific Rvalue types.
@@ -708,7 +712,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             )) => l.is_bits() && r.is_bits(),
             interpret::Operand::Indirect(_) if mir_opt_level >= 2 => {
                 let mplace = op.assert_mem_place(&self.ecx);
-                intern_const_alloc_recursive(&mut self.ecx, None, mplace)
+                intern_const_alloc_recursive(&mut self.ecx, None, mplace, false)
                     .expect("failed to intern alloc");
                 true
             }
@@ -797,13 +801,14 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
     fn visit_constant(&mut self, constant: &mut Constant<'tcx>, location: Location) {
         trace!("visit_constant: {:?}", constant);
         self.super_constant(constant, location);
-        self.eval_constant(constant, self.source_info.unwrap());
+        self.eval_constant(constant);
     }
 
     fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) {
         trace!("visit_statement: {:?}", statement);
         let source_info = statement.source_info;
         self.source_info = Some(source_info);
+        self.lint_root = self.lint_root(source_info);
         if let StatementKind::Assign(box (ref place, ref mut rval)) = statement.kind {
             let place_ty: Ty<'tcx> = place.ty(&self.local_decls, self.tcx).ty;
             if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) {
@@ -855,6 +860,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
         let source_info = terminator.source_info;
         self.source_info = Some(source_info);
         self.super_terminator(terminator, location);
+        self.lint_root = self.lint_root(source_info);
         match &mut terminator.kind {
             TerminatorKind::Assert { expected, ref msg, ref mut cond, .. } => {
                 if let Some(value) = self.eval_operand(&cond, source_info) {
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index 00a39905c02..f8851f7dbdc 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -27,7 +27,7 @@ use rustc_index::vec::{Idx, IndexVec};
 use rustc_target::spec::abi::Abi;
 
 use std::cell::Cell;
-use std::{iter, mem, usize};
+use std::{cmp, iter, mem, usize};
 
 use crate::const_eval::{is_const_fn, is_unstable_const_fn};
 use crate::transform::check_consts::{is_lang_panic_fn, qualifs, ConstKind, Item};
@@ -761,6 +761,7 @@ struct Promoter<'a, 'tcx> {
     source: &'a mut BodyAndCache<'tcx>,
     promoted: BodyAndCache<'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.
@@ -903,7 +904,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
         candidate: Candidate,
         next_promoted_id: usize,
     ) -> Option<BodyAndCache<'tcx>> {
-        let mut operand = {
+        let mut rvalue = {
             let promoted = &mut self.promoted;
             let promoted_id = Promoted::new(next_promoted_id);
             let tcx = self.tcx;
@@ -927,15 +928,70 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
                 Candidate::Ref(loc) => {
                     let ref mut statement = blocks[loc.block].statements[loc.statement_index];
                     match statement.kind {
-                        StatementKind::Assign(box (_, Rvalue::Ref(_, _, ref mut place))) => {
+                        StatementKind::Assign(box (
+                            _,
+                            Rvalue::Ref(ref mut region, borrow_kind, ref mut place),
+                        )) => {
                             // Use the underlying local for this (necessarily interior) borrow.
                             let ty = place.base.ty(local_decls).ty;
                             let span = statement.source_info.span;
 
-                            Operand::Move(Place {
-                                base: mem::replace(&mut place.base, promoted_place(ty, span).base),
-                                projection: List::empty(),
-                            })
+                            let ref_ty = tcx.mk_ref(
+                                tcx.lifetimes.re_static,
+                                ty::TypeAndMut { ty, mutbl: borrow_kind.to_mutbl_lossy() },
+                            );
+
+                            promoted.span = span;
+                            promoted.local_decls[RETURN_PLACE] =
+                                LocalDecl::new_return_place(ref_ty, span);
+
+                            *region = tcx.lifetimes.re_static;
+
+                            let mut projection = vec![PlaceElem::Deref];
+                            projection.extend(place.projection);
+                            place.projection = tcx.intern_place_elems(&projection);
+
+                            // 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;
+                            let promoted_ref = local_decls.push(promoted_ref);
+                            assert_eq!(self.temps.push(TempState::Unpromotable), promoted_ref);
+
+                            let promoted_ref_rvalue =
+                                Rvalue::Use(Operand::Constant(Box::new(Constant {
+                                    span,
+                                    user_ty: None,
+                                    literal: tcx.mk_const(ty::Const {
+                                        ty: ref_ty,
+                                        val: ty::ConstKind::Unevaluated(
+                                            def_id,
+                                            InternalSubsts::identity_for_item(tcx, def_id),
+                                            Some(promoted_id),
+                                        ),
+                                    }),
+                                })));
+                            let promoted_ref_statement = Statement {
+                                source_info: statement.source_info,
+                                kind: StatementKind::Assign(Box::new((
+                                    Place::from(promoted_ref),
+                                    promoted_ref_rvalue,
+                                ))),
+                            };
+                            self.extra_statements.push((loc, promoted_ref_statement));
+
+                            Rvalue::Ref(
+                                tcx.lifetimes.re_static,
+                                borrow_kind,
+                                Place {
+                                    base: mem::replace(
+                                        &mut place.base,
+                                        PlaceBase::Local(promoted_ref),
+                                    ),
+                                    projection: List::empty(),
+                                },
+                            )
                         }
                         _ => bug!(),
                     }
@@ -946,7 +1002,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
                         StatementKind::Assign(box (_, Rvalue::Repeat(ref mut operand, _))) => {
                             let ty = operand.ty(local_decls, self.tcx);
                             let span = statement.source_info.span;
-                            mem::replace(operand, Operand::Copy(promoted_place(ty, span)))
+                            Rvalue::Use(mem::replace(
+                                operand,
+                                Operand::Copy(promoted_place(ty, span)),
+                            ))
                         }
                         _ => bug!(),
                     }
@@ -958,7 +1017,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
                             let ty = args[index].ty(local_decls, self.tcx);
                             let span = terminator.source_info.span;
                             let operand = Operand::Copy(promoted_place(ty, span));
-                            mem::replace(&mut args[index], operand)
+                            Rvalue::Use(mem::replace(&mut args[index], operand))
                         }
                         // We expected a `TerminatorKind::Call` for which we'd like to promote an
                         // argument. `qualify_consts` saw a `TerminatorKind::Call` here, but
@@ -975,13 +1034,13 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
         };
 
         assert_eq!(self.new_block(), START_BLOCK);
-        self.visit_operand(
-            &mut operand,
+        self.visit_rvalue(
+            &mut rvalue,
             Location { block: BasicBlock::new(0), statement_index: usize::MAX },
         );
 
         let span = self.promoted.span;
-        self.assign(RETURN_PLACE, Rvalue::Use(operand), span);
+        self.assign(RETURN_PLACE, rvalue, span);
         Some(self.promoted)
     }
 }
@@ -1020,6 +1079,7 @@ pub fn promote_candidates<'tcx>(
 
     let mut promotions = IndexVec::new();
 
+    let mut extra_statements = vec![];
     for candidate in candidates.into_iter().rev() {
         match candidate {
             Candidate::Repeat(Location { block, statement_index })
@@ -1043,23 +1103,27 @@ pub fn promote_candidates<'tcx>(
         let initial_locals =
             iter::once(LocalDecl::new_return_place(tcx.types.never, body.span)).collect();
 
+        let mut promoted = Body::new(
+            IndexVec::new(),
+            // FIXME: maybe try to filter this to avoid blowing up
+            // memory usage?
+            body.source_scopes.clone(),
+            initial_locals,
+            IndexVec::new(),
+            0,
+            vec![],
+            body.span,
+            vec![],
+            body.generator_kind,
+        );
+        promoted.ignore_interior_mut_in_const_validation = true;
+
         let promoter = Promoter {
-            promoted: BodyAndCache::new(Body::new(
-                IndexVec::new(),
-                // FIXME: maybe try to filter this to avoid blowing up
-                // memory usage?
-                body.source_scopes.clone(),
-                initial_locals,
-                IndexVec::new(),
-                0,
-                vec![],
-                body.span,
-                vec![],
-                body.generator_kind,
-            )),
+            promoted: BodyAndCache::new(promoted),
             tcx,
             source: body,
             temps: &mut temps,
+            extra_statements: &mut extra_statements,
             keep_original: false,
         };
 
@@ -1069,6 +1133,13 @@ pub fn promote_candidates<'tcx>(
         }
     }
 
+    // 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 {
+        body[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 body.basic_blocks_mut() {
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 7c7480339a5..9c1672f6a7a 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -2697,7 +2697,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         let def_id = tcx.hir().local_def_id(ast_const.hir_id);
 
         let mut const_ = ty::Const {
-            val: ty::ConstKind::Unevaluated(def_id, InternalSubsts::identity_for_item(tcx, def_id)),
+            val: ty::ConstKind::Unevaluated(
+                def_id,
+                InternalSubsts::identity_for_item(tcx, def_id),
+                None,
+            ),
             ty,
         };
 
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 874cb9b8a5c..089b4bd8445 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -460,12 +460,16 @@ pub fn name_from_pat(p: &hir::Pat) -> String {
 
 pub fn print_const(cx: &DocContext<'_>, n: &ty::Const<'_>) -> String {
     match n.val {
-        ty::ConstKind::Unevaluated(def_id, _) => {
-            if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(def_id) {
+        ty::ConstKind::Unevaluated(def_id, _, promoted) => {
+            let mut s = if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(def_id) {
                 print_const_expr(cx, cx.tcx.hir().body_owned_by(hir_id))
             } else {
                 inline::print_inlined_const(cx, def_id)
+            };
+            if let Some(promoted) = promoted {
+                s.push_str(&format!("{:?}", promoted))
             }
+            s
         }
         _ => {
             let mut s = n.to_string();
diff --git a/src/test/codegen/consts.rs b/src/test/codegen/consts.rs
index 7d65ad1435e..a5478a03791 100644
--- a/src/test/codegen/consts.rs
+++ b/src/test/codegen/consts.rs
@@ -14,7 +14,7 @@
 
 // This checks the constants from {low,high}_align_const, they share the same
 // constant, but the alignment differs, so the higher one should be used
-// CHECK: [[LOW_HIGH:@[0-9]+]] = {{.*}}, align 4
+// CHECK: [[LOW_HIGH:@[0-9]+]] = {{.*}} getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* @2, i32 0, i32 0, i32 0), {{.*}}, align 8
 
 #[derive(Copy, Clone)]
 
@@ -44,7 +44,7 @@ pub fn inline_enum_const() -> E<i8, i16> {
 #[no_mangle]
 pub fn low_align_const() -> E<i16, [i16; 3]> {
 // Check that low_align_const and high_align_const use the same constant
-// CHECK: i8* align 2 getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0),
+// CHECK: load %"E<i16, [i16; 3]>"*, %"E<i16, [i16; 3]>"** bitcast (<{ i8*, [0 x i8] }>* [[LOW_HIGH]] to %"E<i16, [i16; 3]>"**), align 8
     *&E::A(0)
 }
 
@@ -52,6 +52,6 @@ pub fn low_align_const() -> E<i16, [i16; 3]> {
 #[no_mangle]
 pub fn high_align_const() -> E<i16, i32> {
 // Check that low_align_const and high_align_const use the same constant
-// CHECK: i8* align 4 getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0),
+// CHECK: load %"E<i16, i32>"*, %"E<i16, i32>"** bitcast (<{ i8*, [0 x i8] }>* [[LOW_HIGH]] to %"E<i16, i32>"**), align 8
     *&E::A(0)
 }
diff --git a/src/test/run-fail/promoted_div_by_zero.rs b/src/test/compile-fail/promoted_div_by_zero.rs
index 3fe51a19c20..de55b5360f3 100644
--- a/src/test/run-fail/promoted_div_by_zero.rs
+++ b/src/test/compile-fail/promoted_div_by_zero.rs
@@ -1,6 +1,6 @@
 #![allow(const_err)]
 
-// error-pattern: attempt to divide by zero
+// error-pattern: referenced constant has errors
 
 fn main() {
     let x = &(1 / (1 - 1));
diff --git a/src/test/mir-opt/const_prop/ref_deref.rs b/src/test/mir-opt/const_prop/ref_deref.rs
index d45ffdc8775..6b5101af5fc 100644
--- a/src/test/mir-opt/const_prop/ref_deref.rs
+++ b/src/test/mir-opt/const_prop/ref_deref.rs
@@ -6,7 +6,8 @@ fn main() {
 // START rustc.main.ConstProp.before.mir
 // bb0: {
 //     ...
-//     _2 = &(promoted[0]: i32);
+//     _4 = const main::promoted[0];
+//     _2 = _4;
 //     _1 = (*_2);
 //     ...
 //}
@@ -14,7 +15,8 @@ fn main() {
 // START rustc.main.ConstProp.after.mir
 // bb0: {
 //     ...
-//     _2 = &(promoted[0]: i32);
+//     _4 = const main::promoted[0];
+//     _2 = _4;
 //     _1 = const 4i32;
 //     ...
 // }
diff --git a/src/test/mir-opt/const_prop/slice_len.rs b/src/test/mir-opt/const_prop/slice_len.rs
index d6ff76b34b9..43813e43d36 100644
--- a/src/test/mir-opt/const_prop/slice_len.rs
+++ b/src/test/mir-opt/const_prop/slice_len.rs
@@ -6,7 +6,8 @@ fn main() {
 // START rustc.main.ConstProp.before.mir
 //  bb0: {
 //      ...
-//      _4 = &(promoted[0]: [u32; 3]);
+//      _9 = const main::promoted[0];
+//      _4 = _9;
 //      _3 = _4;
 //      _2 = move _3 as &[u32] (Pointer(Unsize));
 //      ...
@@ -24,7 +25,8 @@ fn main() {
 // START rustc.main.ConstProp.after.mir
 //  bb0: {
 //      ...
-//      _4 = &(promoted[0]: [u32; 3]);
+//      _9 = const main::promoted[0];
+//      _4 = _9;
 //      _3 = _4;
 //      _2 = move _3 as &[u32] (Pointer(Unsize));
 //      ...
diff --git a/src/test/mir-opt/inline/inline-retag.rs b/src/test/mir-opt/inline/inline-retag.rs
index 6cdbcfdb0ad..7b78fc339f2 100644
--- a/src/test/mir-opt/inline/inline-retag.rs
+++ b/src/test/mir-opt/inline/inline-retag.rs
@@ -25,11 +25,11 @@ fn foo(x: &i32, y: &i32) -> bool {
 //         ...
 //         Retag(_3);
 //         Retag(_6);
-//         StorageLive(_9);
-//         _9 = (*_3);
-//         StorageLive(_10);
-//         _10 = (*_6);
-//         _0 = Eq(move _9, move _10);
+//         StorageLive(_11);
+//         _11 = (*_3);
+//         StorageLive(_12);
+//         _12 = (*_6);
+//         _0 = Eq(move _11, move _12);
 //         ...
 //         return;
 //     }
diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs
index 648856b5523..2c20c35e4a4 100644
--- a/src/test/mir-opt/match_false_edges.rs
+++ b/src/test/mir-opt/match_false_edges.rs
@@ -65,7 +65,8 @@ fn main() {
 //  }
 //  bb6: { // binding1 and guard
 //      StorageLive(_6);
-//      _6 = &(((promoted[0]: std::option::Option<i32>) as Some).0: i32);
+//      _11 = const full_tested_match::promoted[0];
+//      _6 = &(((*_11) as Some).0: i32);
 //      _4 = &shallow _2;
 //      StorageLive(_7);
 //      _7 = const guard() -> [return: bb7, unwind: bb1];
diff --git a/src/test/ui/consts/array-literal-index-oob.rs b/src/test/ui/consts/array-literal-index-oob.rs
index 1de6bafd293..59b2fdb7821 100644
--- a/src/test/ui/consts/array-literal-index-oob.rs
+++ b/src/test/ui/consts/array-literal-index-oob.rs
@@ -4,4 +4,5 @@ fn main() {
     &{[1, 2, 3][4]};
     //~^ ERROR index out of bounds
     //~| ERROR reaching this expression at runtime will panic or abort
+    //~| ERROR erroneous constant used [E0080]
 }
diff --git a/src/test/ui/consts/array-literal-index-oob.stderr b/src/test/ui/consts/array-literal-index-oob.stderr
index f3ef16659dd..261c10d1391 100644
--- a/src/test/ui/consts/array-literal-index-oob.stderr
+++ b/src/test/ui/consts/array-literal-index-oob.stderr
@@ -14,5 +14,12 @@ LL |     &{[1, 2, 3][4]};
    |       |
    |       indexing out of bounds: the len is 3 but the index is 4
 
-error: aborting due to 2 previous errors
+error[E0080]: erroneous constant used
+  --> $DIR/array-literal-index-oob.rs:4:5
+   |
+LL |     &{[1, 2, 3][4]};
+   |     ^^^^^^^^^^^^^^^ referenced constant has errors
+
+error: aborting due to 3 previous errors
 
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/conditional_array_execution.rs b/src/test/ui/consts/const-eval/conditional_array_execution.rs
index 96f67c92a5e..107d0817daf 100644
--- a/src/test/ui/consts/const-eval/conditional_array_execution.rs
+++ b/src/test/ui/consts/const-eval/conditional_array_execution.rs
@@ -10,4 +10,5 @@ const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
 fn main() {
     println!("{}", FOO);
     //~^ ERROR
+    //~| ERROR erroneous constant used [E0080]
 }
diff --git a/src/test/ui/consts/const-eval/conditional_array_execution.stderr b/src/test/ui/consts/const-eval/conditional_array_execution.stderr
index ec18f8f011d..f161ab6f198 100644
--- a/src/test/ui/consts/const-eval/conditional_array_execution.stderr
+++ b/src/test/ui/consts/const-eval/conditional_array_execution.stderr
@@ -18,6 +18,12 @@ error[E0080]: evaluation of constant expression failed
 LL |     println!("{}", FOO);
    |                    ^^^ referenced constant has errors
 
-error: aborting due to previous error
+error[E0080]: erroneous constant used
+  --> $DIR/conditional_array_execution.rs:11:20
+   |
+LL |     println!("{}", FOO);
+   |                    ^^^ referenced constant has errors
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs
index a5f04d088b6..21dbe72418a 100644
--- a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs
+++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs
@@ -17,6 +17,8 @@ const Z: usize = bar(double, 2); // FIXME: should fail to typeck someday
 fn main() {
     assert_eq!(Y, 4);
     //~^ ERROR evaluation of constant expression failed
+    //~| ERROR erroneous constant used [E0080]
     assert_eq!(Z, 4);
     //~^ ERROR evaluation of constant expression failed
+    //~| ERROR erroneous constant used [E0080]
 }
diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr
index 19f37fa0079..ebbd18bbd25 100644
--- a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr
+++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr
@@ -14,8 +14,16 @@ LL |     assert_eq!(Y, 4);
    |
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
+error[E0080]: erroneous constant used
+  --> $DIR/const_fn_ptr_fail2.rs:18:5
+   |
+LL |     assert_eq!(Y, 4);
+   |     ^^^^^^^^^^^^^^^^^ referenced constant has errors
+   |
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
 error[E0080]: evaluation of constant expression failed
-  --> $DIR/const_fn_ptr_fail2.rs:20:5
+  --> $DIR/const_fn_ptr_fail2.rs:21:5
    |
 LL |     assert_eq!(Z, 4);
    |     ^^^^^^^^^^^-^^^^^
@@ -24,6 +32,14 @@ LL |     assert_eq!(Z, 4);
    |
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
-error: aborting due to 2 previous errors
+error[E0080]: erroneous constant used
+  --> $DIR/const_fn_ptr_fail2.rs:21:5
+   |
+LL |     assert_eq!(Z, 4);
+   |     ^^^^^^^^^^^^^^^^^ referenced constant has errors
+   |
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/issue-43197.rs b/src/test/ui/consts/const-eval/issue-43197.rs
index 849c81ad449..23890be6934 100644
--- a/src/test/ui/consts/const-eval/issue-43197.rs
+++ b/src/test/ui/consts/const-eval/issue-43197.rs
@@ -14,4 +14,6 @@ fn main() {
     println!("{} {}", X, Y);
     //~^ ERROR evaluation of constant expression failed
     //~| ERROR evaluation of constant expression failed
+    //~| ERROR erroneous constant used [E0080]
+    //~| ERROR erroneous constant used [E0080]
 }
diff --git a/src/test/ui/consts/const-eval/issue-43197.stderr b/src/test/ui/consts/const-eval/issue-43197.stderr
index a1b3a05ed41..50bc07d459c 100644
--- a/src/test/ui/consts/const-eval/issue-43197.stderr
+++ b/src/test/ui/consts/const-eval/issue-43197.stderr
@@ -26,12 +26,24 @@ error[E0080]: evaluation of constant expression failed
 LL |     println!("{} {}", X, Y);
    |                       ^ referenced constant has errors
 
+error[E0080]: erroneous constant used
+  --> $DIR/issue-43197.rs:14:23
+   |
+LL |     println!("{} {}", X, Y);
+   |                       ^ referenced constant has errors
+
 error[E0080]: evaluation of constant expression failed
   --> $DIR/issue-43197.rs:14:26
    |
 LL |     println!("{} {}", X, Y);
    |                          ^ referenced constant has errors
 
-error: aborting due to 2 previous errors
+error[E0080]: erroneous constant used
+  --> $DIR/issue-43197.rs:14:26
+   |
+LL |     println!("{} {}", X, Y);
+   |                          ^ referenced constant has errors
+
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/issue-44578.rs b/src/test/ui/consts/const-eval/issue-44578.rs
index 7da9256bb39..607f78f70b3 100644
--- a/src/test/ui/consts/const-eval/issue-44578.rs
+++ b/src/test/ui/consts/const-eval/issue-44578.rs
@@ -25,5 +25,6 @@ impl Foo for u16 {
 
 fn main() {
     println!("{}", <Bar<u16, u8> as Foo>::AMT);
-    //~^ ERROR E0080
+    //~^ ERROR erroneous constant used [E0080]
+    //~| ERROR evaluation of constant expression failed [E0080]
 }
diff --git a/src/test/ui/consts/const-eval/issue-44578.stderr b/src/test/ui/consts/const-eval/issue-44578.stderr
index f4323713e68..5c0ac17aceb 100644
--- a/src/test/ui/consts/const-eval/issue-44578.stderr
+++ b/src/test/ui/consts/const-eval/issue-44578.stderr
@@ -4,6 +4,12 @@ error[E0080]: evaluation of constant expression failed
 LL |     println!("{}", <Bar<u16, u8> as Foo>::AMT);
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
 
-error: aborting due to previous error
+error[E0080]: erroneous constant used
+  --> $DIR/issue-44578.rs:27:20
+   |
+LL |     println!("{}", <Bar<u16, u8> as Foo>::AMT);
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/issue-50814.rs b/src/test/ui/consts/const-eval/issue-50814.rs
index e589126a942..5c3635e4650 100644
--- a/src/test/ui/consts/const-eval/issue-50814.rs
+++ b/src/test/ui/consts/const-eval/issue-50814.rs
@@ -12,11 +12,13 @@ impl Unsigned for U8 {
 struct Sum<A,B>(A,B);
 
 impl<A: Unsigned, B: Unsigned> Unsigned for Sum<A,B> {
-    const MAX: u8 = A::MAX + B::MAX; //~ ERROR any use of this value will cause an error
+    const MAX: u8 = A::MAX + B::MAX;
+    //~^ ERROR any use of this value will cause an error [const_err]
 }
 
 fn foo<T>(_: T) -> &'static u8 {
-    &Sum::<U8,U8>::MAX //~ ERROR E0080
+    &Sum::<U8,U8>::MAX
+    //~^ ERROR E0080
 }
 
 fn main() {
diff --git a/src/test/ui/consts/const-eval/issue-50814.stderr b/src/test/ui/consts/const-eval/issue-50814.stderr
index f8b017e4b53..2e5167a99a2 100644
--- a/src/test/ui/consts/const-eval/issue-50814.stderr
+++ b/src/test/ui/consts/const-eval/issue-50814.stderr
@@ -9,7 +9,7 @@ LL |     const MAX: u8 = A::MAX + B::MAX;
    = note: `#[deny(const_err)]` on by default
 
 error[E0080]: evaluation of constant expression failed
-  --> $DIR/issue-50814.rs:19:5
+  --> $DIR/issue-50814.rs:20:5
    |
 LL |     &Sum::<U8,U8>::MAX
    |     ^-----------------
diff --git a/src/test/ui/consts/const-eval/promoted_errors.rs b/src/test/ui/consts/const-eval/promoted_errors.rs
index 2eed8ca7d32..6d83839a8d1 100644
--- a/src/test/ui/consts/const-eval/promoted_errors.rs
+++ b/src/test/ui/consts/const-eval/promoted_errors.rs
@@ -10,11 +10,13 @@ fn main() {
     println!("{}", 1/(1-1));
     //~^ ERROR attempt to divide by zero [const_err]
     //~| ERROR const_err
+    //~| ERROR erroneous constant used [E0080]
     let _x = 1/(1-1);
     //~^ ERROR const_err
     println!("{}", 1/(false as u32));
     //~^ ERROR attempt to divide by zero [const_err]
     //~| ERROR const_err
+    //~| ERROR erroneous constant used [E0080]
     let _x = 1/(false as u32);
     //~^ ERROR const_err
 }
diff --git a/src/test/ui/consts/const-eval/promoted_errors.stderr b/src/test/ui/consts/const-eval/promoted_errors.stderr
index 8f17ef05f23..32672ca8566 100644
--- a/src/test/ui/consts/const-eval/promoted_errors.stderr
+++ b/src/test/ui/consts/const-eval/promoted_errors.stderr
@@ -22,29 +22,42 @@ error: reaching this expression at runtime will panic or abort
 LL |     println!("{}", 1/(1-1));
    |                    ^^^^^^^ dividing by zero
 
+error[E0080]: erroneous constant used
+  --> $DIR/promoted_errors.rs:10:20
+   |
+LL |     println!("{}", 1/(1-1));
+   |                    ^^^^^^^ referenced constant has errors
+
 error: attempt to divide by zero
-  --> $DIR/promoted_errors.rs:13:14
+  --> $DIR/promoted_errors.rs:14:14
    |
 LL |     let _x = 1/(1-1);
    |              ^^^^^^^
 
 error: attempt to divide by zero
-  --> $DIR/promoted_errors.rs:15:20
+  --> $DIR/promoted_errors.rs:16:20
    |
 LL |     println!("{}", 1/(false as u32));
    |                    ^^^^^^^^^^^^^^^^
 
 error: reaching this expression at runtime will panic or abort
-  --> $DIR/promoted_errors.rs:15:20
+  --> $DIR/promoted_errors.rs:16:20
    |
 LL |     println!("{}", 1/(false as u32));
    |                    ^^^^^^^^^^^^^^^^ dividing by zero
 
+error[E0080]: erroneous constant used
+  --> $DIR/promoted_errors.rs:16:20
+   |
+LL |     println!("{}", 1/(false as u32));
+   |                    ^^^^^^^^^^^^^^^^ referenced constant has errors
+
 error: attempt to divide by zero
-  --> $DIR/promoted_errors.rs:18:14
+  --> $DIR/promoted_errors.rs:20:14
    |
 LL |     let _x = 1/(false as u32);
    |              ^^^^^^^^^^^^^^^^
 
-error: aborting due to 7 previous errors
+error: aborting due to 9 previous errors
 
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/promoted_errors2.rs b/src/test/ui/consts/const-eval/promoted_errors2.rs
index ae680b4f107..8ea6cdf6a8f 100644
--- a/src/test/ui/consts/const-eval/promoted_errors2.rs
+++ b/src/test/ui/consts/const-eval/promoted_errors2.rs
@@ -11,11 +11,13 @@ fn main() {
     println!("{}", 1/(1-1));
     //~^ ERROR attempt to divide by zero [const_err]
     //~| ERROR const_err
+    //~| ERROR erroneous constant used [E0080]
     let _x = 1/(1-1);
     //~^ ERROR const_err
     println!("{}", 1/(false as u32));
     //~^ ERROR attempt to divide by zero [const_err]
     //~| ERROR const_err
+    //~| ERROR erroneous constant used [E0080]
     let _x = 1/(false as u32);
     //~^ ERROR const_err
 }
diff --git a/src/test/ui/consts/const-eval/promoted_errors2.stderr b/src/test/ui/consts/const-eval/promoted_errors2.stderr
index 60a3cba6e1f..e7a73aa8118 100644
--- a/src/test/ui/consts/const-eval/promoted_errors2.stderr
+++ b/src/test/ui/consts/const-eval/promoted_errors2.stderr
@@ -28,29 +28,42 @@ error: reaching this expression at runtime will panic or abort
 LL |     println!("{}", 1/(1-1));
    |                    ^^^^^^^ dividing by zero
 
+error[E0080]: erroneous constant used
+  --> $DIR/promoted_errors2.rs:11:20
+   |
+LL |     println!("{}", 1/(1-1));
+   |                    ^^^^^^^ referenced constant has errors
+
 error: attempt to divide by zero
-  --> $DIR/promoted_errors2.rs:14:14
+  --> $DIR/promoted_errors2.rs:15:14
    |
 LL |     let _x = 1/(1-1);
    |              ^^^^^^^
 
 error: attempt to divide by zero
-  --> $DIR/promoted_errors2.rs:16:20
+  --> $DIR/promoted_errors2.rs:17:20
    |
 LL |     println!("{}", 1/(false as u32));
    |                    ^^^^^^^^^^^^^^^^
 
 error: reaching this expression at runtime will panic or abort
-  --> $DIR/promoted_errors2.rs:16:20
+  --> $DIR/promoted_errors2.rs:17:20
    |
 LL |     println!("{}", 1/(false as u32));
    |                    ^^^^^^^^^^^^^^^^ dividing by zero
 
+error[E0080]: erroneous constant used
+  --> $DIR/promoted_errors2.rs:17:20
+   |
+LL |     println!("{}", 1/(false as u32));
+   |                    ^^^^^^^^^^^^^^^^ referenced constant has errors
+
 error: attempt to divide by zero
-  --> $DIR/promoted_errors2.rs:19:14
+  --> $DIR/promoted_errors2.rs:21:14
    |
 LL |     let _x = 1/(false as u32);
    |              ^^^^^^^^^^^^^^^^
 
-error: aborting due to 8 previous errors
+error: aborting due to 10 previous errors
 
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/ub-nonnull.stderr b/src/test/ui/consts/const-eval/ub-nonnull.stderr
index 80d80a98675..c2446d14040 100644
--- a/src/test/ui/consts/const-eval/ub-nonnull.stderr
+++ b/src/test/ui/consts/const-eval/ub-nonnull.stderr
@@ -13,7 +13,7 @@ LL | / const OUT_OF_BOUNDS_PTR: NonNull<u8> = { unsafe {
 LL | |     let ptr: &[u8; 256] = mem::transmute(&0u8); // &0 gets promoted so it does not dangle
 LL | |     // Use address-of-element for pointer arithmetic. This could wrap around to NULL!
 LL | |     let out_of_bounds_ptr = &ptr[255];
-   | |                             ^^^^^^^^^ Memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of allocation 6 which has size 1
+   | |                             ^^^^^^^^^ Memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of allocation 8 which has size 1
 LL | |     mem::transmute(out_of_bounds_ptr)
 LL | | } };
    | |____-
diff --git a/src/test/ui/consts/miri_unleashed/non_const_fn.rs b/src/test/ui/consts/miri_unleashed/non_const_fn.rs
index 32a713ebaa4..23b0cfa8321 100644
--- a/src/test/ui/consts/miri_unleashed/non_const_fn.rs
+++ b/src/test/ui/consts/miri_unleashed/non_const_fn.rs
@@ -11,5 +11,7 @@ const C: () = foo(); //~ WARN: skipping const checks
 //~^ WARN any use of this value will cause an error
 
 fn main() {
-    println!("{:?}", C); //~ ERROR: evaluation of constant expression failed
+    println!("{:?}", C);
+    //~^ ERROR: evaluation of constant expression failed
+    //~| ERROR: erroneous constant used [E0080]
 }
diff --git a/src/test/ui/consts/miri_unleashed/non_const_fn.stderr b/src/test/ui/consts/miri_unleashed/non_const_fn.stderr
index 75f532a81bd..a7364ddf72c 100644
--- a/src/test/ui/consts/miri_unleashed/non_const_fn.stderr
+++ b/src/test/ui/consts/miri_unleashed/non_const_fn.stderr
@@ -24,6 +24,12 @@ error[E0080]: evaluation of constant expression failed
 LL |     println!("{:?}", C);
    |                      ^ referenced constant has errors
 
-error: aborting due to previous error
+error[E0080]: erroneous constant used
+  --> $DIR/non_const_fn.rs:14:22
+   |
+LL |     println!("{:?}", C);
+   |                      ^ referenced constant has errors
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/zst_no_llvm_alloc.rs b/src/test/ui/consts/zst_no_llvm_alloc.rs
index 5d779355400..2a41f708c2b 100644
--- a/src/test/ui/consts/zst_no_llvm_alloc.rs
+++ b/src/test/ui/consts/zst_no_llvm_alloc.rs
@@ -7,13 +7,15 @@ static FOO: Foo = Foo;
 
 fn main() {
     let x: &'static () = &();
-    assert_eq!(x as *const () as usize, 1);
+    assert_ne!(x as *const () as usize, 1);
     let x: &'static Foo = &Foo;
-    assert_eq!(x as *const Foo as usize, 4);
+    assert_ne!(x as *const Foo as usize, 4);
 
     // statics must have a unique address
     assert_ne!(&FOO as *const Foo as usize, 4);
 
-    assert_eq!(<Vec<i32>>::new().as_ptr(), <&[i32]>::default().as_ptr());
-    assert_eq!(<Box<[i32]>>::default().as_ptr(), (&[]).as_ptr());
+    // FIXME this two tests should be assert_eq!
+    // this stopped working since we are promoting to constants instead of statics
+    assert_ne!(<Vec<i32>>::new().as_ptr(), <&[i32]>::default().as_ptr());
+    assert_ne!(<Box<[i32]>>::default().as_ptr(), (&[]).as_ptr());
 }
diff --git a/src/test/ui/invalid_const_promotion.rs b/src/test/ui/invalid_const_promotion.rs
deleted file mode 100644
index 5d7664cefb3..00000000000
--- a/src/test/ui/invalid_const_promotion.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-// run-pass
-
-#![allow(unused_mut)]
-// ignore-wasm32
-// ignore-emscripten
-// ignore-sgx no processes
-
-// compile-flags: -C debug_assertions=yes
-
-#![stable(feature = "rustc", since = "1.0.0")]
-#![feature(const_fn, rustc_private, staged_api, rustc_attrs)]
-#![allow(const_err)]
-
-extern crate libc;
-
-use std::env;
-use std::process::{Command, Stdio};
-
-// this will panic in debug mode and overflow in release mode
-//
-// NB we give bar an unused argument because otherwise memoization
-// of the const fn kicks in, causing a different code path in the
-// compiler to be executed (see PR #66294).
-#[stable(feature = "rustc", since = "1.0.0")]
-#[rustc_const_stable(feature = "rustc", since = "1.0.0")]
-#[rustc_promotable]
-const fn bar(_: bool) -> usize { 0 - 1 }
-
-fn foo() {
-    let _: &'static _ = &bar(true);
-}
-
-#[cfg(unix)]
-fn check_status(status: std::process::ExitStatus)
-{
-    use std::os::unix::process::ExitStatusExt;
-
-    assert!(status.signal() == Some(libc::SIGILL)
-            || status.signal() == Some(libc::SIGTRAP)
-            || status.signal() == Some(libc::SIGABRT));
-}
-
-#[cfg(not(unix))]
-fn check_status(status: std::process::ExitStatus)
-{
-    assert!(!status.success());
-}
-
-fn main() {
-    let args: Vec<String> = env::args().collect();
-    if args.len() > 1 && args[1] == "test" {
-        foo();
-        return;
-    }
-
-    let mut p = Command::new(&args[0])
-        .stdout(Stdio::piped())
-        .stdin(Stdio::piped())
-        .arg("test").output().unwrap();
-    check_status(p.status);
-}
diff --git a/src/test/ui/symbol-names/impl1.legacy.stderr b/src/test/ui/symbol-names/impl1.legacy.stderr
index 53ab2f9878f..affb5537b18 100644
--- a/src/test/ui/symbol-names/impl1.legacy.stderr
+++ b/src/test/ui/symbol-names/impl1.legacy.stderr
@@ -46,13 +46,13 @@ error: def-path(bar::<impl foo::Foo>::baz)
 LL |         #[rustc_def_path]
    |         ^^^^^^^^^^^^^^^^^
 
-error: symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$_$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method17h92c563325b7ff21aE)
+error: symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$_$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method17hf07584432cd4d8beE)
   --> $DIR/impl1.rs:62:13
    |
 LL |             #[rustc_symbol_name]
    |             ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method::h92c563325b7ff21a)
+error: demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method::hf07584432cd4d8be)
   --> $DIR/impl1.rs:62:13
    |
 LL |             #[rustc_symbol_name]