about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorPieter Agten <pieter.agten@fortanix.com>2019-12-05 08:48:15 +0100
committerPieter Agten <pieter.agten@fortanix.com>2019-12-05 08:48:15 +0100
commit9a428e119480e49834a60ea8aaf9c4678c915598 (patch)
treefd537725624c07a32c99a37f3811e9cd30b1556a /src
parent3ee0f48429e6571a87320f2f2e56a48e6717cff1 (diff)
parentaeaaf8f640c919074983edd8366ab3d10321f2b5 (diff)
downloadrust-9a428e119480e49834a60ea8aaf9c4678c915598.tar.gz
rust-9a428e119480e49834a60ea8aaf9c4678c915598.zip
Merge branch 'master' into feature/print-msg-from-elf-entrypoint
Diffstat (limited to 'src')
-rw-r--r--src/libcore/intrinsics.rs1
-rw-r--r--src/librustc/ty/constness.rs115
-rw-r--r--src/librustc_data_structures/obligation_forest/mod.rs13
-rw-r--r--src/librustc_data_structures/obligation_forest/tests.rs30
-rw-r--r--src/librustc_feature/active.rs4
-rw-r--r--src/librustc_metadata/rmeta/decoder.rs6
-rw-r--r--src/librustc_metadata/rmeta/encoder.rs6
-rw-r--r--src/librustc_mir/const_eval.rs18
-rw-r--r--src/librustc_mir/interpret/intrinsics.rs129
-rw-r--r--src/librustc_mir/interpret/machine.rs2
-rw-r--r--src/librustc_mir/interpret/terminator.rs17
-rw-r--r--src/librustc_mir/transform/check_consts/ops.rs16
-rw-r--r--src/librustc_mir/transform/check_consts/validation.rs20
-rw-r--r--src/librustc_mir/transform/const_prop.rs2
-rw-r--r--src/librustc_mir/transform/qualify_min_const_fn.rs56
-rw-r--r--src/libsyntax_pos/symbol.rs29
-rw-r--r--src/test/ui/consts/const-eval/const-eval-intrinsic-promotion.rs6
-rw-r--r--src/test/ui/consts/const-eval/const-eval-intrinsic-promotion.stderr13
-rw-r--r--src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs4
-rw-r--r--src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr4
-rw-r--r--src/test/ui/feature-gates/feature-gate-const_transmute.rs2
-rw-r--r--src/test/ui/feature-gates/feature-gate-const_transmute.stderr4
-rw-r--r--src/test/ui/traits/cycle-cache-err-60010.stderr4
m---------src/tools/miri14
24 files changed, 311 insertions, 204 deletions
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index d4952f53bf7..19928f30f2e 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -939,6 +939,7 @@ extern "rust-intrinsic" {
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_unstable(feature = "const_transmute")]
     pub fn transmute<T, U>(e: T) -> U;
 
     /// Returns `true` if the actual type given as `T` requires drop
diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs
index 676916f530a..268015a5624 100644
--- a/src/librustc/ty/constness.rs
+++ b/src/librustc/ty/constness.rs
@@ -2,7 +2,8 @@ use crate::ty::query::Providers;
 use crate::hir::def_id::DefId;
 use crate::hir;
 use crate::ty::TyCtxt;
-use syntax_pos::symbol::Symbol;
+use syntax_pos::symbol::{sym, Symbol};
+use rustc_target::spec::abi::Abi;
 use crate::hir::map::blocks::FnLikeNode;
 use syntax::attr;
 
@@ -35,12 +36,51 @@ impl<'tcx> TyCtxt<'tcx> {
         }
     }
 
+    /// Returns `true` if the `def_id` refers to an intrisic which we've whitelisted
+    /// for being called from stable `const fn`s (`min_const_fn`).
+    ///
+    /// Adding more intrinsics requires sign-off from @rust-lang/lang.
+    ///
+    /// This list differs from the list in `is_const_intrinsic` in the sense that any item on this
+    /// list must be on the `is_const_intrinsic` list, too, because if an intrinsic is callable from
+    /// stable, it must be callable at all.
+    fn is_intrinsic_min_const_fn(self, def_id: DefId) -> bool {
+        match self.item_name(def_id) {
+            | sym::size_of
+            | sym::min_align_of
+            | sym::needs_drop
+            // Arithmetic:
+            | sym::add_with_overflow // ~> .overflowing_add
+            | sym::sub_with_overflow // ~> .overflowing_sub
+            | sym::mul_with_overflow // ~> .overflowing_mul
+            | sym::wrapping_add // ~> .wrapping_add
+            | sym::wrapping_sub // ~> .wrapping_sub
+            | sym::wrapping_mul // ~> .wrapping_mul
+            | sym::saturating_add // ~> .saturating_add
+            | sym::saturating_sub // ~> .saturating_sub
+            | sym::unchecked_shl // ~> .wrapping_shl
+            | sym::unchecked_shr // ~> .wrapping_shr
+            | sym::rotate_left // ~> .rotate_left
+            | sym::rotate_right // ~> .rotate_right
+            | sym::ctpop // ~> .count_ones
+            | sym::ctlz // ~> .leading_zeros
+            | sym::cttz // ~> .trailing_zeros
+            | sym::bswap // ~> .swap_bytes
+            | sym::bitreverse // ~> .reverse_bits
+            => true,
+            _ => false,
+        }
+    }
+
     /// Returns `true` if this function must conform to `min_const_fn`
     pub fn is_min_const_fn(self, def_id: DefId) -> bool {
         // Bail out if the signature doesn't contain `const`
         if !self.is_const_fn_raw(def_id) {
             return false;
         }
+        if let Abi::RustIntrinsic = self.fn_sig(def_id).abi() {
+            return self.is_intrinsic_min_const_fn(def_id);
+        }
 
         if self.features().staged_api {
             // in order for a libstd function to be considered min_const_fn
@@ -63,13 +103,82 @@ impl<'tcx> TyCtxt<'tcx> {
 
 
 pub fn provide(providers: &mut Providers<'_>) {
-    /// only checks whether the function has a `const` modifier
+    /// Const evaluability whitelist is here to check evaluability at the
+    /// top level beforehand.
+    fn is_const_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> Option<bool> {
+        match tcx.fn_sig(def_id).abi() {
+            Abi::RustIntrinsic |
+            Abi::PlatformIntrinsic => {
+                // FIXME: deduplicate these two lists as much as possible
+                match tcx.item_name(def_id) {
+                    // Keep this list in the same order as the match patterns in
+                    // `librustc_mir/interpret/intrinsics.rs`
+
+                    // This whitelist is a list of intrinsics that have a miri-engine implementation
+                    // and can thus be called when enabling enough feature gates. The similar
+                    // whitelist in `is_intrinsic_min_const_fn` (in this file), exists for allowing
+                    // the intrinsics to be called by stable const fns.
+                    | sym::caller_location
+
+                    | sym::min_align_of
+                    | sym::pref_align_of
+                    | sym::needs_drop
+                    | sym::size_of
+                    | sym::type_id
+                    | sym::type_name
+
+                    | sym::ctpop
+                    | sym::cttz
+                    | sym::cttz_nonzero
+                    | sym::ctlz
+                    | sym::ctlz_nonzero
+                    | sym::bswap
+                    | sym::bitreverse
+
+                    | sym::wrapping_add
+                    | sym::wrapping_sub
+                    | sym::wrapping_mul
+                    | sym::add_with_overflow
+                    | sym::sub_with_overflow
+                    | sym::mul_with_overflow
+
+                    | sym::saturating_add
+                    | sym::saturating_sub
+
+                    | sym::unchecked_shl
+                    | sym::unchecked_shr
+
+                    | sym::rotate_left
+                    | sym::rotate_right
+
+                    | sym::ptr_offset_from
+
+                    | sym::transmute
+
+                    | sym::simd_insert
+
+                    | sym::simd_extract
+
+                    => Some(true),
+
+                    _ => Some(false)
+                }
+            }
+            _ => None
+        }
+    }
+
+    /// Checks whether the function has a `const` modifier or, in case it is an intrinsic, whether
+    /// said intrinsic is on the whitelist for being const callable.
     fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
         let hir_id = tcx.hir().as_local_hir_id(def_id)
                               .expect("Non-local call to local provider is_const_fn");
 
         let node = tcx.hir().get(hir_id);
-        if let Some(fn_like) = FnLikeNode::from_node(node) {
+
+        if let Some(whitelisted) = is_const_intrinsic(tcx, def_id) {
+            whitelisted
+        } else if let Some(fn_like) = FnLikeNode::from_node(node) {
             fn_like.constness() == hir::Constness::Const
         } else if let hir::Node::Ctor(_) = node {
             true
diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs
index 958ab617cb3..8a5badd0afc 100644
--- a/src/librustc_data_structures/obligation_forest/mod.rs
+++ b/src/librustc_data_structures/obligation_forest/mod.rs
@@ -395,7 +395,16 @@ impl<O: ForestObligation> ObligationForest<O> {
         let mut errors = vec![];
         let mut stalled = true;
 
-        for index in 0..self.nodes.len() {
+        // Note that the loop body can append new nodes, and those new nodes
+        // will then be processed by subsequent iterations of the loop.
+        //
+        // We can't use an iterator for the loop because `self.nodes` is
+        // appended to and the borrow checker would complain. We also can't use
+        // `for index in 0..self.nodes.len() { ... }` because the range would
+        // be computed with the initial length, and we would miss the appended
+        // nodes. Therefore we use a `while` loop.
+        let mut index = 0;
+        while index < self.nodes.len() {
             let node = &mut self.nodes[index];
 
             debug!("process_obligations: node {} == {:?}", index, node);
@@ -406,6 +415,7 @@ impl<O: ForestObligation> ObligationForest<O> {
             // out of sync with `nodes`. It's not very common, but it does
             // happen, and code in `compress` has to allow for it.
             if node.state.get() != NodeState::Pending {
+                index += 1;
                 continue;
             }
             let result = processor.process_obligation(&mut node.obligation);
@@ -441,6 +451,7 @@ impl<O: ForestObligation> ObligationForest<O> {
                     });
                 }
             }
+            index += 1;
         }
 
         if stalled {
diff --git a/src/librustc_data_structures/obligation_forest/tests.rs b/src/librustc_data_structures/obligation_forest/tests.rs
index 54b6f6d0adc..995c99bfec3 100644
--- a/src/librustc_data_structures/obligation_forest/tests.rs
+++ b/src/librustc_data_structures/obligation_forest/tests.rs
@@ -70,6 +70,7 @@ fn push_pop() {
                 "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
                 "B" => ProcessResult::Error("B is for broken"),
                 "C" => ProcessResult::Changed(vec![]),
+                "A.1" | "A.2" | "A.3" => ProcessResult::Unchanged,
                 _ => unreachable!(),
             }
         }, |_| {}), DoCompleted::Yes);
@@ -94,6 +95,7 @@ fn push_pop() {
                 "A.2" => ProcessResult::Unchanged,
                 "A.3" => ProcessResult::Changed(vec!["A.3.i"]),
                 "D" => ProcessResult::Changed(vec!["D.1", "D.2"]),
+                "A.3.i" | "D.1" | "D.2" => ProcessResult::Unchanged,
                 _ => unreachable!(),
             }
         }, |_| {}), DoCompleted::Yes);
@@ -113,6 +115,7 @@ fn push_pop() {
                 "A.3.i" => ProcessResult::Changed(vec![]),
                 "D.1" => ProcessResult::Changed(vec!["D.1.i"]),
                 "D.2" => ProcessResult::Changed(vec!["D.2.i"]),
+                "D.1.i" | "D.2.i" => ProcessResult::Unchanged,
                 _ => unreachable!(),
             }
         }, |_| {}), DoCompleted::Yes);
@@ -161,35 +164,38 @@ fn success_in_grandchildren() {
         forest.process_obligations(&mut C(|obligation| {
             match *obligation {
                 "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
+                "A.1" => ProcessResult::Changed(vec![]),
+                "A.2" => ProcessResult::Changed(vec!["A.2.i", "A.2.ii"]),
+                "A.3" => ProcessResult::Changed(vec![]),
+                "A.2.i" | "A.2.ii" => ProcessResult::Unchanged,
                 _ => unreachable!(),
             }
         }, |_| {}), DoCompleted::Yes);
-    assert!(ok.unwrap().is_empty());
+    let mut ok = ok.unwrap();
+    ok.sort();
+    assert_eq!(ok, vec!["A.1", "A.3"]);
     assert!(err.is_empty());
 
     let Outcome { completed: ok, errors: err, .. } =
         forest.process_obligations(&mut C(|obligation| {
             match *obligation {
-                "A.1" => ProcessResult::Changed(vec![]),
-                "A.2" => ProcessResult::Changed(vec!["A.2.i", "A.2.ii"]),
-                "A.3" => ProcessResult::Changed(vec![]),
+                "A.2.i" => ProcessResult::Unchanged,
+                "A.2.ii" => ProcessResult::Changed(vec![]),
                 _ => unreachable!(),
             }
         }, |_| {}), DoCompleted::Yes);
-    let mut ok = ok.unwrap();
-    ok.sort();
-    assert_eq!(ok, vec!["A.1", "A.3"]);
+    assert_eq!(ok.unwrap(), vec!["A.2.ii"]);
     assert!(err.is_empty());
 
     let Outcome { completed: ok, errors: err, .. } =
         forest.process_obligations(&mut C(|obligation| {
             match *obligation {
                 "A.2.i" => ProcessResult::Changed(vec!["A.2.i.a"]),
-                "A.2.ii" => ProcessResult::Changed(vec![]),
+                "A.2.i.a" => ProcessResult::Unchanged,
                 _ => unreachable!(),
             }
         }, |_| {}), DoCompleted::Yes);
-    assert_eq!(ok.unwrap(), vec!["A.2.ii"]);
+    assert!(ok.unwrap().is_empty());
     assert!(err.is_empty());
 
     let Outcome { completed: ok, errors: err, .. } =
@@ -222,6 +228,7 @@ fn to_errors_no_throw() {
         forest.process_obligations(&mut C(|obligation| {
             match *obligation {
                 "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
+                "A.1" | "A.2" | "A.3" => ProcessResult::Unchanged,
                 _ => unreachable!(),
             }
         }, |_|{}), DoCompleted::Yes);
@@ -243,6 +250,7 @@ fn diamond() {
         forest.process_obligations(&mut C(|obligation| {
             match *obligation {
                 "A" => ProcessResult::Changed(vec!["A.1", "A.2"]),
+                "A.1" | "A.2" => ProcessResult::Unchanged,
                 _ => unreachable!(),
             }
         }, |_|{}), DoCompleted::Yes);
@@ -254,6 +262,7 @@ fn diamond() {
             match *obligation {
                 "A.1" => ProcessResult::Changed(vec!["D"]),
                 "A.2" => ProcessResult::Changed(vec!["D"]),
+                "D" => ProcessResult::Unchanged,
                 _ => unreachable!(),
             }
         }, |_|{}), DoCompleted::Yes);
@@ -282,6 +291,7 @@ fn diamond() {
         forest.process_obligations(&mut C(|obligation| {
             match *obligation {
                 "A'" => ProcessResult::Changed(vec!["A'.1", "A'.2"]),
+                "A'.1" | "A'.2" => ProcessResult::Unchanged,
                 _ => unreachable!(),
             }
         }, |_|{}), DoCompleted::Yes);
@@ -293,6 +303,7 @@ fn diamond() {
             match *obligation {
                 "A'.1" => ProcessResult::Changed(vec!["D'", "A'"]),
                 "A'.2" => ProcessResult::Changed(vec!["D'"]),
+                "D'" | "A'" => ProcessResult::Unchanged,
                 _ => unreachable!(),
             }
         }, |_|{}), DoCompleted::Yes);
@@ -370,6 +381,7 @@ fn orphan() {
                 "B" => ProcessResult::Unchanged,
                 "C1" => ProcessResult::Changed(vec![]),
                 "C2" => ProcessResult::Changed(vec![]),
+                "D" | "E" => ProcessResult::Unchanged,
                 _ => unreachable!(),
             }
         }, |_|{}), DoCompleted::Yes);
diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs
index 16d8ada9f24..fc880b9e929 100644
--- a/src/librustc_feature/active.rs
+++ b/src/librustc_feature/active.rs
@@ -408,10 +408,6 @@ declare_features! (
     /// Allows using `#[doc(keyword = "...")]`.
     (active, doc_keyword, "1.28.0", Some(51315), None),
 
-    /// Allows reinterpretation of the bits of a value of one type as another
-    /// type during const eval.
-    (active, const_transmute, "1.29.0", Some(53605), None),
-
     /// Allows using `try {...}` expressions.
     (active, try_blocks, "1.29.0", Some(31436), None),
 
diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs
index 42db642cd4d..6edd17fe9ab 100644
--- a/src/librustc_metadata/rmeta/decoder.rs
+++ b/src/librustc_metadata/rmeta/decoder.rs
@@ -1360,10 +1360,16 @@ impl<'a, 'tcx> CrateMetadata {
         }
     }
 
+    // This replicates some of the logic of the crate-local `is_const_fn_raw` query, because we
+    // don't serialize constness for tuple variant and tuple struct constructors.
     fn is_const_fn_raw(&self, id: DefIndex) -> bool {
         let constness = match self.kind(id) {
             EntryKind::Method(data) => data.decode(self).fn_data.constness,
             EntryKind::Fn(data) => data.decode(self).constness,
+            // Some intrinsics can be const fn. While we could recompute this (at least until we
+            // stop having hardcoded whitelists and move to stability attributes), it seems cleaner
+            // to treat all const fns equally.
+            EntryKind::ForeignFn(data) => data.decode(self).constness,
             EntryKind::Variant(..) | EntryKind::Struct(..) => hir::Constness::Const,
             _ => hir::Constness::NotConst,
         };
diff --git a/src/librustc_metadata/rmeta/encoder.rs b/src/librustc_metadata/rmeta/encoder.rs
index 3a318ddc1e1..fb70e10c84f 100644
--- a/src/librustc_metadata/rmeta/encoder.rs
+++ b/src/librustc_metadata/rmeta/encoder.rs
@@ -1525,7 +1525,11 @@ impl EncodeContext<'tcx> {
             hir::ForeignItemKind::Fn(_, ref names, _) => {
                 let data = FnData {
                     asyncness: hir::IsAsync::NotAsync,
-                    constness: hir::Constness::NotConst,
+                    constness: if self.tcx.is_const_fn_raw(def_id) {
+                        hir::Constness::Const
+                    } else {
+                        hir::Constness::NotConst
+                    },
                     param_names: self.encode_fn_param_names(names),
                 };
                 EntryKind::ForeignFn(self.lazy(data))
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index a3eac1eecf0..968a8a71ba0 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -328,20 +328,32 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
         false // for now, we don't enforce validity
     }
 
-    fn find_fn(
+    fn find_mir_or_eval_fn(
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx>],
         ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>,
         _unwind: Option<mir::BasicBlock> // unwinding is not supported in consts
     ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> {
-        debug!("eval_fn_call: {:?}", instance);
+        debug!("find_mir_or_eval_fn: {:?}", instance);
+
         // Only check non-glue functions
         if let ty::InstanceDef::Item(def_id) = instance.def {
             // Execution might have wandered off into other crates, so we cannot do a stability-
             // sensitive check here.  But we can at least rule out functions that are not const
             // at all.
-            if !ecx.tcx.is_const_fn_raw(def_id) {
+            if ecx.tcx.is_const_fn_raw(def_id) {
+                // If this function is a `const fn` then as an optimization we can query this
+                // evaluation immediately.
+                //
+                // For the moment we only do this for functions which take no arguments
+                // (or all arguments are ZSTs) so that we don't memoize too much.
+                if args.iter().all(|a| a.layout.is_zst()) {
+                    let gid = GlobalId { instance, promoted: None };
+                    ecx.eval_const_fn_call(gid, ret)?;
+                    return Ok(None);
+                }
+            } else {
                 // Some functions we support even if they are non-const -- but avoid testing
                 // that for const fn!  We certainly do *not* want to actually call the fn
                 // though, so be sure we return here.
diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs
index 75fc6b389e8..ad5df5aff1a 100644
--- a/src/librustc_mir/interpret/intrinsics.rs
+++ b/src/librustc_mir/interpret/intrinsics.rs
@@ -2,7 +2,7 @@
 //! looking at their MIR. Intrinsics/functions supported here are shared by CTFE
 //! and miri.
 
-use syntax::symbol::Symbol;
+use syntax_pos::symbol::{sym, Symbol};
 use syntax_pos::Span;
 use rustc::ty;
 use rustc::ty::layout::{LayoutOf, Primitive, Size};
@@ -22,7 +22,7 @@ mod caller_location;
 mod type_name;
 
 fn numeric_intrinsic<'tcx, Tag>(
-    name: &str,
+    name: Symbol,
     bits: u128,
     kind: Primitive,
 ) -> InterpResult<'tcx, Scalar<Tag>> {
@@ -32,11 +32,11 @@ fn numeric_intrinsic<'tcx, Tag>(
     };
     let extra = 128 - size.bits() as u128;
     let bits_out = match name {
-        "ctpop" => bits.count_ones() as u128,
-        "ctlz" => bits.leading_zeros() as u128 - extra,
-        "cttz" => (bits << extra).trailing_zeros() as u128 - extra,
-        "bswap" => (bits << extra).swap_bytes(),
-        "bitreverse" => (bits << extra).reverse_bits(),
+        sym::ctpop => bits.count_ones() as u128,
+        sym::ctlz => bits.leading_zeros() as u128 - extra,
+        sym::cttz => (bits << extra).trailing_zeros() as u128 - extra,
+        sym::bswap => (bits << extra).swap_bytes(),
+        sym::bitreverse => (bits << extra).reverse_bits(),
         _ => bug!("not a numeric intrinsic: {}", name),
     };
     Ok(Scalar::from_uint(bits_out, size))
@@ -51,9 +51,9 @@ crate fn eval_nullary_intrinsic<'tcx>(
     substs: SubstsRef<'tcx>,
 ) -> InterpResult<'tcx, &'tcx ty::Const<'tcx>> {
     let tp_ty = substs.type_at(0);
-    let name = &*tcx.item_name(def_id).as_str();
+    let name = tcx.item_name(def_id);
     Ok(match name {
-        "type_name" => {
+        sym::type_name => {
             let alloc = type_name::alloc_type_name(tcx, tp_ty);
             tcx.mk_const(ty::Const {
                 val: ty::ConstKind::Value(ConstValue::Slice {
@@ -64,20 +64,20 @@ crate fn eval_nullary_intrinsic<'tcx>(
                 ty: tcx.mk_static_str(),
             })
         },
-        "needs_drop" => ty::Const::from_bool(tcx, tp_ty.needs_drop(tcx, param_env)),
-        "size_of" |
-        "min_align_of" |
-        "pref_align_of" => {
+        sym::needs_drop => ty::Const::from_bool(tcx, tp_ty.needs_drop(tcx, param_env)),
+        sym::size_of |
+        sym::min_align_of |
+        sym::pref_align_of => {
             let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(e)))?;
             let n = match name {
-                "pref_align_of" => layout.align.pref.bytes(),
-                "min_align_of" => layout.align.abi.bytes(),
-                "size_of" => layout.size.bytes(),
+                sym::pref_align_of => layout.align.pref.bytes(),
+                sym::min_align_of => layout.align.abi.bytes(),
+                sym::size_of => layout.size.bytes(),
                 _ => bug!(),
             };
             ty::Const::from_usize(tcx, n)
         },
-        "type_id" => ty::Const::from_bits(
+        sym::type_id => ty::Const::from_bits(
             tcx,
             tcx.type_id_hash(tp_ty).into(),
             param_env.and(tcx.types.u64),
@@ -96,30 +96,32 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         ret: Option<(PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>,
     ) -> InterpResult<'tcx, bool> {
         let substs = instance.substs;
-        let intrinsic_name = &*self.tcx.item_name(instance.def_id()).as_str();
+        let intrinsic_name = self.tcx.item_name(instance.def_id());
 
         // We currently do not handle any intrinsics that are *allowed* to diverge,
         // but `transmute` could lack a return place in case of UB.
         let (dest, ret) = match ret {
             Some(p) => p,
             None => match intrinsic_name {
-                "transmute" => throw_ub!(Unreachable),
+                sym::transmute => throw_ub!(Unreachable),
                 _ => return Ok(false),
             }
         };
 
+        // Keep the patterns in this match ordered the same as the list in
+        // `src/librustc/ty/constness.rs`
         match intrinsic_name {
-            "caller_location" => {
+            sym::caller_location => {
                 let location = self.alloc_caller_location_for_span(span);
                 self.write_scalar(location.ptr, dest)?;
             }
 
-            "min_align_of" |
-            "pref_align_of" |
-            "needs_drop" |
-            "size_of" |
-            "type_id" |
-            "type_name" => {
+            sym::min_align_of |
+            sym::pref_align_of |
+            sym::needs_drop |
+            sym::size_of |
+            sym::type_id |
+            sym::type_name => {
                 let gid = GlobalId {
                     instance,
                     promoted: None,
@@ -129,13 +131,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 self.copy_op(val, dest)?;
             }
 
-            | "ctpop"
-            | "cttz"
-            | "cttz_nonzero"
-            | "ctlz"
-            | "ctlz_nonzero"
-            | "bswap"
-            | "bitreverse" => {
+            | sym::ctpop
+            | sym::cttz
+            | sym::cttz_nonzero
+            | sym::ctlz
+            | sym::ctlz_nonzero
+            | sym::bswap
+            | sym::bitreverse => {
                 let ty = substs.type_at(0);
                 let layout_of = self.layout_of(ty)?;
                 let val = self.read_scalar(args[0])?.not_undef()?;
@@ -144,31 +146,32 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     ty::layout::Abi::Scalar(ref scalar) => scalar.value,
                     _ => throw_unsup!(TypeNotPrimitive(ty)),
                 };
-                let out_val = if intrinsic_name.ends_with("_nonzero") {
-                    if bits == 0 {
-                        throw_ub_format!("`{}` called on 0", intrinsic_name);
-                    }
-                    numeric_intrinsic(intrinsic_name.trim_end_matches("_nonzero"), bits, kind)?
-                } else {
-                    numeric_intrinsic(intrinsic_name, bits, kind)?
+                let (nonzero, intrinsic_name) = match intrinsic_name {
+                    sym::cttz_nonzero => (true, sym::cttz),
+                    sym::ctlz_nonzero => (true, sym::ctlz),
+                    other => (false, other),
                 };
+                if nonzero && bits == 0 {
+                    throw_ub_format!("`{}_nonzero` called on 0", intrinsic_name);
+                }
+                let out_val = numeric_intrinsic(intrinsic_name, bits, kind)?;
                 self.write_scalar(out_val, dest)?;
             }
-            | "wrapping_add"
-            | "wrapping_sub"
-            | "wrapping_mul"
-            | "add_with_overflow"
-            | "sub_with_overflow"
-            | "mul_with_overflow" => {
+            | sym::wrapping_add
+            | sym::wrapping_sub
+            | sym::wrapping_mul
+            | sym::add_with_overflow
+            | sym::sub_with_overflow
+            | sym::mul_with_overflow => {
                 let lhs = self.read_immediate(args[0])?;
                 let rhs = self.read_immediate(args[1])?;
                 let (bin_op, ignore_overflow) = match intrinsic_name {
-                    "wrapping_add" => (BinOp::Add, true),
-                    "wrapping_sub" => (BinOp::Sub, true),
-                    "wrapping_mul" => (BinOp::Mul, true),
-                    "add_with_overflow" => (BinOp::Add, false),
-                    "sub_with_overflow" => (BinOp::Sub, false),
-                    "mul_with_overflow" => (BinOp::Mul, false),
+                    sym::wrapping_add => (BinOp::Add, true),
+                    sym::wrapping_sub => (BinOp::Sub, true),
+                    sym::wrapping_mul => (BinOp::Mul, true),
+                    sym::add_with_overflow => (BinOp::Add, false),
+                    sym::sub_with_overflow => (BinOp::Sub, false),
+                    sym::mul_with_overflow => (BinOp::Mul, false),
                     _ => bug!("Already checked for int ops")
                 };
                 if ignore_overflow {
@@ -177,10 +180,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     self.binop_with_overflow(bin_op, lhs, rhs, dest)?;
                 }
             }
-            "saturating_add" | "saturating_sub" => {
+            sym::saturating_add | sym::saturating_sub => {
                 let l = self.read_immediate(args[0])?;
                 let r = self.read_immediate(args[1])?;
-                let is_add = intrinsic_name == "saturating_add";
+                let is_add = intrinsic_name == sym::saturating_add;
                 let (val, overflowed, _ty) = self.overflowing_binary_op(if is_add {
                     BinOp::Add
                 } else {
@@ -220,12 +223,12 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 };
                 self.write_scalar(val, dest)?;
             }
-            "unchecked_shl" | "unchecked_shr" => {
+            sym::unchecked_shl | sym::unchecked_shr => {
                 let l = self.read_immediate(args[0])?;
                 let r = self.read_immediate(args[1])?;
                 let bin_op = match intrinsic_name {
-                    "unchecked_shl" => BinOp::Shl,
-                    "unchecked_shr" => BinOp::Shr,
+                    sym::unchecked_shl => BinOp::Shl,
+                    sym::unchecked_shr => BinOp::Shr,
                     _ => bug!("Already checked for int ops")
                 };
                 let (val, overflowed, _ty) = self.overflowing_binary_op(bin_op, l, r)?;
@@ -236,7 +239,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 }
                 self.write_scalar(val, dest)?;
             }
-            "rotate_left" | "rotate_right" => {
+            sym::rotate_left | sym::rotate_right => {
                 // rotate_left: (X << (S % BW)) | (X >> ((BW - S) % BW))
                 // rotate_right: (X << ((BW - S) % BW)) | (X >> (S % BW))
                 let layout = self.layout_of(substs.type_at(0))?;
@@ -247,7 +250,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let width_bits = layout.size.bits() as u128;
                 let shift_bits = raw_shift_bits % width_bits;
                 let inv_shift_bits = (width_bits - shift_bits) % width_bits;
-                let result_bits = if intrinsic_name == "rotate_left" {
+                let result_bits = if intrinsic_name == sym::rotate_left {
                     (val_bits << shift_bits) | (val_bits >> inv_shift_bits)
                 } else {
                     (val_bits >> shift_bits) | (val_bits << inv_shift_bits)
@@ -257,7 +260,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 self.write_scalar(result, dest)?;
             }
 
-            "ptr_offset_from" => {
+            sym::ptr_offset_from => {
                 let isize_layout = self.layout_of(self.tcx.types.isize)?;
                 let a = self.read_immediate(args[0])?.to_scalar()?;
                 let b = self.read_immediate(args[1])?.to_scalar()?;
@@ -303,10 +306,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 }
             }
 
-            "transmute" => {
+            sym::transmute => {
                 self.copy_op_transmute(args[0], dest)?;
             }
-            "simd_insert" => {
+            sym::simd_insert => {
                 let index = u64::from(self.read_scalar(args[1])?.to_u32()?);
                 let elem = args[2];
                 let input = args[0];
@@ -337,7 +340,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     self.copy_op(value, place)?;
                 }
             }
-            "simd_extract" => {
+            sym::simd_extract => {
                 let index = u64::from(self.read_scalar(args[1])?.to_u32()?);
                 let (len, e_ty) = args[0].layout.ty.simd_size_and_type(self.tcx.tcx);
                 assert!(
diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs
index 2ecc8d88ad3..74206ad2873 100644
--- a/src/librustc_mir/interpret/machine.rs
+++ b/src/librustc_mir/interpret/machine.rs
@@ -146,7 +146,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
     /// nor just jump to `ret`, but instead push their own stack frame.)
     /// Passing `dest`and `ret` in the same `Option` proved very annoying when only one of them
     /// was used.
-    fn find_fn(
+    fn find_mir_or_eval_fn(
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx, Self::PointerTag>],
diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs
index 06c3969fbc5..b8dc15f451d 100644
--- a/src/librustc_mir/interpret/terminator.rs
+++ b/src/librustc_mir/interpret/terminator.rs
@@ -266,20 +266,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             ty::InstanceDef::DropGlue(..) |
             ty::InstanceDef::CloneShim(..) |
             ty::InstanceDef::Item(_) => {
-                // If this function is a `const fn` then as an optimization we can query this
-                // evaluation immediately.
-                //
-                // For the moment we only do this for functions which take no arguments
-                // (or all arguments are ZSTs) so that we don't memoize too much.
-                if self.tcx.is_const_fn_raw(instance.def.def_id()) &&
-                   args.iter().all(|a| a.layout.is_zst())
-                {
-                    let gid = GlobalId { instance, promoted: None };
-                    return self.eval_const_fn_call(gid, ret);
-                }
-
                 // We need MIR for this fn
-                let body = match M::find_fn(self, instance, args, ret, unwind)? {
+                let body = match M::find_mir_or_eval_fn(self, instance, args, ret, unwind)? {
                     Some(body) => body,
                     None => return Ok(()),
                 };
@@ -445,7 +433,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     /// Evaluate a const function where all arguments (if any) are zero-sized types.
     /// The evaluation is memoized thanks to the query system.
-    fn eval_const_fn_call(
+    // FIXME: Consider moving this to `const_eval.rs`.
+    pub (crate) fn eval_const_fn_call(
         &mut self,
         gid: GlobalId<'tcx>,
         ret: Option<(PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>,
diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs
index a4f12a4e54f..aec3cf04a97 100644
--- a/src/librustc_mir/transform/check_consts/ops.rs
+++ b/src/librustc_mir/transform/check_consts/ops.rs
@@ -327,22 +327,6 @@ impl NonConstOp for ThreadLocalAccess {
 }
 
 #[derive(Debug)]
-pub struct Transmute;
-impl NonConstOp for Transmute {
-    fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
-        Some(tcx.features().const_transmute)
-    }
-
-    fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
-        feature_err(
-            &item.tcx.sess.parse_sess, sym::const_transmute, span,
-            &format!("The use of std::mem::transmute() is gated in {}s", item.const_kind())
-        )
-        .emit();
-    }
-}
-
-#[derive(Debug)]
 pub struct UnionAccess;
 impl NonConstOp for UnionAccess {
     fn is_allowed_in_item(&self, item: &Item<'_, '_>) -> bool {
diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs
index 663a5243e8f..f44bac126f2 100644
--- a/src/librustc_mir/transform/check_consts/validation.rs
+++ b/src/librustc_mir/transform/check_consts/validation.rs
@@ -8,7 +8,6 @@ use rustc::traits::{self, TraitEngine};
 use rustc::ty::cast::CastTy;
 use rustc::ty::{self, TyCtxt};
 use rustc_index::bit_set::BitSet;
-use rustc_target::spec::abi::Abi;
 use rustc_error_codes::*;
 use syntax::symbol::sym;
 use syntax_pos::Span;
@@ -202,7 +201,7 @@ impl Validator<'a, 'mir, 'tcx> {
         let Item { tcx, body, def_id, const_kind, ..  } = *self.item;
 
         let use_min_const_fn_checks =
-            tcx.is_min_const_fn(def_id)
+            (const_kind == Some(ConstKind::ConstFn) && tcx.is_min_const_fn(def_id))
             && !tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you;
 
         if use_min_const_fn_checks {
@@ -564,23 +563,6 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
                 };
 
                 // At this point, we are calling a function whose `DefId` is known...
-
-                if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = self.tcx.fn_sig(def_id).abi() {
-                    assert!(!self.tcx.is_const_fn(def_id));
-
-                    if self.tcx.item_name(def_id) == sym::transmute {
-                        self.check_op(ops::Transmute);
-                        return;
-                    }
-
-                    // To preserve the current semantics, we return early, allowing all
-                    // intrinsics (except `transmute`) to pass unchecked to miri.
-                    //
-                    // FIXME: We should keep a whitelist of allowed intrinsics (or at least a
-                    // blacklist of unimplemented ones) and fail here instead.
-                    return;
-                }
-
                 if self.tcx.is_const_fn(def_id) {
                     return;
                 }
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index a99ca71d167..95de635d634 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -128,7 +128,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
         false
     }
 
-    fn find_fn(
+    fn find_mir_or_eval_fn(
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
         _instance: ty::Instance<'tcx>,
         _args: &[OpTy<'tcx>],
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index e40d6a5952e..3030d2e646b 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -2,7 +2,6 @@ use rustc::hir::def_id::DefId;
 use rustc::hir;
 use rustc::mir::*;
 use rustc::ty::{self, Predicate, Ty, TyCtxt, adjustment::{PointerCast}};
-use rustc_target::spec::abi;
 use std::borrow::Cow;
 use syntax_pos::Span;
 use syntax::symbol::{sym, Symbol};
@@ -356,18 +355,8 @@ fn check_terminator(
         } => {
             let fn_ty = func.ty(body, tcx);
             if let ty::FnDef(def_id, _) = fn_ty.kind {
-
-                // some intrinsics are waved through if called inside the
-                // standard library. Users never need to call them directly
-                match tcx.fn_sig(def_id).abi() {
-                    abi::Abi::RustIntrinsic => if !is_intrinsic_whitelisted(tcx, def_id) {
-                        return Err((
-                            span,
-                            "can only call a curated list of intrinsics in `min_const_fn`".into(),
-                        ))
-                    },
-                    abi::Abi::Rust if tcx.is_min_const_fn(def_id) => {},
-                    abi::Abi::Rust => return Err((
+                if !tcx.is_min_const_fn(def_id) {
+                    return Err((
                         span,
                         format!(
                             "can only call other `const fn` within a `const fn`, \
@@ -375,14 +364,7 @@ fn check_terminator(
                             func,
                         )
                         .into(),
-                    )),
-                    abi => return Err((
-                        span,
-                        format!(
-                            "cannot call functions with `{}` abi in `min_const_fn`",
-                            abi,
-                        ).into(),
-                    )),
+                    ));
                 }
 
                 check_operand(tcx, func, span, def_id, body)?;
@@ -409,35 +391,3 @@ fn check_terminator(
         },
     }
 }
-
-/// Returns `true` if the `def_id` refers to an intrisic which we've whitelisted
-/// for being called from stable `const fn`s (`min_const_fn`).
-///
-/// Adding more intrinsics requires sign-off from @rust-lang/lang.
-fn is_intrinsic_whitelisted(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
-    match &*tcx.item_name(def_id).as_str() {
-        | "size_of"
-        | "min_align_of"
-        | "needs_drop"
-        // Arithmetic:
-        | "add_with_overflow" // ~> .overflowing_add
-        | "sub_with_overflow" // ~> .overflowing_sub
-        | "mul_with_overflow" // ~> .overflowing_mul
-        | "wrapping_add" // ~> .wrapping_add
-        | "wrapping_sub" // ~> .wrapping_sub
-        | "wrapping_mul" // ~> .wrapping_mul
-        | "saturating_add" // ~> .saturating_add
-        | "saturating_sub" // ~> .saturating_sub
-        | "unchecked_shl" // ~> .wrapping_shl
-        | "unchecked_shr" // ~> .wrapping_shr
-        | "rotate_left" // ~> .rotate_left
-        | "rotate_right" // ~> .rotate_right
-        | "ctpop" // ~> .count_ones
-        | "ctlz" // ~> .leading_zeros
-        | "cttz" // ~> .trailing_zeros
-        | "bswap" // ~> .swap_bytes
-        | "bitreverse" // ~> .reverse_bits
-        => true,
-        _ => false,
-    }
-}
diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs
index 88a325112ac..2af66711d3c 100644
--- a/src/libsyntax_pos/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -121,6 +121,7 @@ symbols! {
         abi_vectorcall,
         abi_x86_interrupt,
         aborts,
+        add_with_overflow,
         advanced_slice_patterns,
         adx_target_feature,
         alias,
@@ -171,7 +172,10 @@ symbols! {
         box_patterns,
         box_syntax,
         braced_empty_structs,
+        bswap,
+        bitreverse,
         C,
+        caller_location,
         cdylib,
         cfg,
         cfg_attr,
@@ -226,6 +230,11 @@ symbols! {
         crate_name,
         crate_type,
         crate_visibility_modifier,
+        ctpop,
+        cttz,
+        cttz_nonzero,
+        ctlz,
+        ctlz_nonzero,
         custom_attribute,
         custom_derive,
         custom_inner_attributes,
@@ -431,6 +440,7 @@ symbols! {
         member_constraints,
         message,
         meta,
+        min_align_of,
         min_const_fn,
         min_const_unsafe_fn,
         mips_target_feature,
@@ -440,11 +450,13 @@ symbols! {
         more_struct_aliases,
         move_val_init,
         movbe_target_feature,
+        mul_with_overflow,
         must_use,
         naked,
         naked_functions,
         name,
         needs_allocator,
+        needs_drop,
         needs_panic_runtime,
         negate_unsigned,
         never,
@@ -520,6 +532,7 @@ symbols! {
         poll_with_tls_context,
         powerpc_target_feature,
         precise_pointer_size_matching,
+        pref_align_of,
         prelude,
         prelude_import,
         primitive,
@@ -536,6 +549,7 @@ symbols! {
         proc_macro_non_items,
         proc_macro_path_invoc,
         profiler_runtime,
+        ptr_offset_from,
         pub_restricted,
         pushpop_unsafe,
         quad_precision_float,
@@ -571,6 +585,8 @@ symbols! {
         Return,
         rhs,
         rlib,
+        rotate_left,
+        rotate_right,
         rt,
         rtm_target_feature,
         rust,
@@ -638,14 +654,19 @@ symbols! {
         rvalue_static_promotion,
         sanitize,
         sanitizer_runtime,
+        saturating_add,
+        saturating_sub,
         _Self,
         self_in_typedefs,
         self_struct_ctor,
         should_panic,
         simd,
+        simd_extract,
         simd_ffi,
+        simd_insert,
         since,
         size,
+        size_of,
         slice_patterns,
         slicing_syntax,
         soft,
@@ -673,6 +694,7 @@ symbols! {
         structural_match,
         struct_variant,
         sty,
+        sub_with_overflow,
         suggestion,
         target_feature,
         target_has_atomic,
@@ -708,6 +730,8 @@ symbols! {
         Ty,
         ty,
         type_alias_impl_trait,
+        type_id,
+        type_name,
         TyCtxt,
         TyKind,
         type_alias_enum_variants,
@@ -720,6 +744,8 @@ symbols! {
         u64,
         u8,
         unboxed_closures,
+        unchecked_shl,
+        unchecked_shr,
         underscore_const_names,
         underscore_imports,
         underscore_lifetimes,
@@ -753,6 +779,9 @@ symbols! {
         while_let,
         windows,
         windows_subsystem,
+        wrapping_add,
+        wrapping_sub,
+        wrapping_mul,
         Yield,
     }
 }
diff --git a/src/test/ui/consts/const-eval/const-eval-intrinsic-promotion.rs b/src/test/ui/consts/const-eval/const-eval-intrinsic-promotion.rs
new file mode 100644
index 00000000000..bdcf537859c
--- /dev/null
+++ b/src/test/ui/consts/const-eval/const-eval-intrinsic-promotion.rs
@@ -0,0 +1,6 @@
+#![feature(core_intrinsics)]
+fn main() {
+    // Test that calls to intrinsics are never promoted
+    let x: &'static usize =
+        &std::intrinsics::size_of::<i32>(); //~ ERROR temporary value dropped while borrowed
+}
diff --git a/src/test/ui/consts/const-eval/const-eval-intrinsic-promotion.stderr b/src/test/ui/consts/const-eval/const-eval-intrinsic-promotion.stderr
new file mode 100644
index 00000000000..78143042ece
--- /dev/null
+++ b/src/test/ui/consts/const-eval/const-eval-intrinsic-promotion.stderr
@@ -0,0 +1,13 @@
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/const-eval-intrinsic-promotion.rs:5:10
+   |
+LL |     let x: &'static usize =
+   |            -------------- type annotation requires that borrow lasts for `'static`
+LL |         &std::intrinsics::size_of::<i32>();
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+LL | }
+   | - temporary value is freed at the end of this statement
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0716`.
diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs
index 7c6a574a211..6469a65700d 100644
--- a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs
+++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs
@@ -7,7 +7,7 @@ extern "C" {
 const extern fn bar() {
     unsafe {
         regular_in_block();
-        //~^ ERROR: cannot call functions with `"C"` abi in `min_const_fn`
+        //~^ ERROR: can only call other `const fn` within a `const fn`
     }
 }
 
@@ -16,7 +16,7 @@ extern fn regular() {}
 const extern fn foo() {
     unsafe {
         regular();
-        //~^ ERROR: cannot call functions with `"C"` abi in `min_const_fn`
+        //~^ ERROR: can only call other `const fn` within a `const fn`
     }
 }
 
diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr
index d8bdf0a57cf..eed279ecf75 100644
--- a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr
+++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr
@@ -1,4 +1,4 @@
-error[E0723]: cannot call functions with `"C"` abi in `min_const_fn`
+error[E0723]: can only call other `const fn` within a `const fn`, but `const regular_in_block` is not stable as `const fn`
   --> $DIR/const-extern-fn-call-extern-fn.rs:9:9
    |
 LL |         regular_in_block();
@@ -7,7 +7,7 @@ LL |         regular_in_block();
    = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
-error[E0723]: cannot call functions with `"C"` abi in `min_const_fn`
+error[E0723]: can only call other `const fn` within a `const fn`, but `const regular` is not stable as `const fn`
   --> $DIR/const-extern-fn-call-extern-fn.rs:18:9
    |
 LL |         regular();
diff --git a/src/test/ui/feature-gates/feature-gate-const_transmute.rs b/src/test/ui/feature-gates/feature-gate-const_transmute.rs
index 6a5bbec77fd..da532643d94 100644
--- a/src/test/ui/feature-gates/feature-gate-const_transmute.rs
+++ b/src/test/ui/feature-gates/feature-gate-const_transmute.rs
@@ -4,6 +4,6 @@ use std::mem;
 struct Foo(u32);
 
 const TRANSMUTED_U32: u32 = unsafe { mem::transmute(Foo(3)) };
-//~^ ERROR The use of std::mem::transmute() is gated in constants
+//~^ ERROR `std::intrinsics::transmute` is not yet stable as a const fn
 
 fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-const_transmute.stderr b/src/test/ui/feature-gates/feature-gate-const_transmute.stderr
index 41b653d98dc..772e8d29478 100644
--- a/src/test/ui/feature-gates/feature-gate-const_transmute.stderr
+++ b/src/test/ui/feature-gates/feature-gate-const_transmute.stderr
@@ -1,12 +1,10 @@
-error[E0658]: The use of std::mem::transmute() is gated in constants
+error: `std::intrinsics::transmute` is not yet stable as a const fn
   --> $DIR/feature-gate-const_transmute.rs:6:38
    |
 LL | const TRANSMUTED_U32: u32 = unsafe { mem::transmute(Foo(3)) };
    |                                      ^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/53605
    = help: add `#![feature(const_transmute)]` to the crate attributes to enable
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/traits/cycle-cache-err-60010.stderr b/src/test/ui/traits/cycle-cache-err-60010.stderr
index f439de88261..295845b1146 100644
--- a/src/test/ui/traits/cycle-cache-err-60010.stderr
+++ b/src/test/ui/traits/cycle-cache-err-60010.stderr
@@ -6,7 +6,7 @@ LL |     _parse: <ParseQuery as Query<RootDatabase>>::Data,
    |
    = note: required because of the requirements on the impl of `Query<RootDatabase>` for `ParseQuery`
 
-error[E0275]: overflow evaluating the requirement `RootDatabase: SourceDatabase`
+error[E0275]: overflow evaluating the requirement `Runtime<RootDatabase>: std::panic::RefUnwindSafe`
   --> $DIR/cycle-cache-err-60010.rs:31:5
    |
 LL |     type Storage;
@@ -17,6 +17,8 @@ LL | impl Database for RootDatabase {
 LL |     type Storage = SalsaStorage;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: required because it appears within the type `RootDatabase`
+   = note: required because of the requirements on the impl of `SourceDatabase` for `RootDatabase`
    = note: required because of the requirements on the impl of `Query<RootDatabase>` for `ParseQuery`
    = note: required because it appears within the type `SalsaStorage`
 
diff --git a/src/tools/miri b/src/tools/miri
-Subproject c388361cc2db82568d5e90fefea864f0af8d35e
+Subproject a0ba079b6af0f8c07c33dd8af72a51c997e5896