about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/bootstrap/native.rs6
-rw-r--r--src/liballoc/tests/binary_heap.rs2
-rw-r--r--src/liballoc/tests/slice.rs21
-rw-r--r--src/libcore/tests/slice.rs17
-rw-r--r--src/librustc/mir/interpret/allocation.rs73
-rw-r--r--src/librustc/mir/interpret/pointer.rs8
-rw-r--r--src/librustc/mir/interpret/value.rs34
-rw-r--r--src/librustc/session/config.rs106
-rw-r--r--src/librustc/session/mod.rs65
-rw-r--r--src/librustc_errors/emitter.rs67
-rw-r--r--src/librustc_mir/const_eval.rs22
-rw-r--r--src/librustc_mir/interpret/machine.rs40
-rw-r--r--src/librustc_mir/interpret/memory.rs10
-rw-r--r--src/librustc_mir/interpret/operand.rs38
-rw-r--r--src/librustc_mir/interpret/place.rs36
-rw-r--r--src/librustc_mir/interpret/traits.rs2
-rw-r--r--src/librustc_mir/transform/qualify_min_const_fn.rs7
-rw-r--r--src/librustdoc/config.rs19
-rw-r--r--src/librustdoc/core.rs29
-rw-r--r--src/librustdoc/test.rs2
-rw-r--r--src/libsyntax/json.rs31
-rw-r--r--src/libsyntax/parse/lexer/mod.rs1
-rw-r--r--src/libsyntax/test_snippet.rs1
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs6
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr6
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs7
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr6
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs6
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr6
-rw-r--r--src/test/ui/lint/use_suggestion_json.rs3
-rw-r--r--src/test/ui/lint/use_suggestion_json.stderr140
-rw-r--r--src/tools/compiletest/src/json.rs7
-rw-r--r--src/tools/compiletest/src/runtest.rs46
33 files changed, 444 insertions, 426 deletions
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index fde40b0d1b4..96aed729345 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -156,8 +156,10 @@ impl Step for Llvm {
            .define("LLVM_DEFAULT_TARGET_TRIPLE", target);
 
         if builder.config.llvm_thin_lto && !emscripten {
-            cfg.define("LLVM_ENABLE_LTO", "Thin")
-               .define("LLVM_ENABLE_LLD", "ON");
+            cfg.define("LLVM_ENABLE_LTO", "Thin");
+            if !target.contains("apple") {
+               cfg.define("LLVM_ENABLE_LLD", "ON");
+            }
         }
 
         // By default, LLVM will automatically find OCaml and, if it finds it,
diff --git a/src/liballoc/tests/binary_heap.rs b/src/liballoc/tests/binary_heap.rs
index 0930f8dacd4..0685fa943c0 100644
--- a/src/liballoc/tests/binary_heap.rs
+++ b/src/liballoc/tests/binary_heap.rs
@@ -282,7 +282,7 @@ fn assert_covariance() {
 //
 // Destructors must be called exactly once per element.
 #[test]
-#[cfg(not(miri))] // Miri does not support panics nor entropy
+#[cfg(not(miri))] // Miri does not support catching panics
 fn panic_safe() {
     static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0);
 
diff --git a/src/liballoc/tests/slice.rs b/src/liballoc/tests/slice.rs
index b54c128a024..ad2cd7c95eb 100644
--- a/src/liballoc/tests/slice.rs
+++ b/src/liballoc/tests/slice.rs
@@ -389,7 +389,7 @@ fn test_reverse() {
 }
 
 #[test]
-#[cfg(not(miri))] // Miri does not support entropy
+#[cfg(not(miri))] // Miri is too slow
 fn test_sort() {
     let mut rng = thread_rng();
 
@@ -466,10 +466,19 @@ fn test_sort() {
 }
 
 #[test]
-#[cfg(not(miri))] // Miri does not support entropy
 fn test_sort_stability() {
-    for len in (2..25).chain(500..510) {
-        for _ in 0..10 {
+    #[cfg(not(miri))] // Miri is too slow
+    let large_range = 500..510;
+    #[cfg(not(miri))] // Miri is too slow
+    let rounds = 10;
+
+    #[cfg(miri)]
+    let large_range = 0..0; // empty range
+    #[cfg(miri)]
+    let rounds = 1;
+
+    for len in (2..25).chain(large_range) {
+        for _ in 0..rounds {
             let mut counts = [0; 10];
 
             // create a vector like [(6, 1), (5, 1), (6, 2), ...],
@@ -1397,7 +1406,7 @@ fn test_box_slice_clone() {
 #[test]
 #[allow(unused_must_use)] // here, we care about the side effects of `.clone()`
 #[cfg_attr(target_os = "emscripten", ignore)]
-#[cfg(not(miri))] // Miri does not support threads nor entropy
+#[cfg(not(miri))] // Miri does not support threads
 fn test_box_slice_clone_panics() {
     use std::sync::Arc;
     use std::sync::atomic::{AtomicUsize, Ordering};
@@ -1589,7 +1598,7 @@ thread_local!(static SILENCE_PANIC: Cell<bool> = Cell::new(false));
 
 #[test]
 #[cfg_attr(target_os = "emscripten", ignore)] // no threads
-#[cfg(not(miri))] // Miri does not support threads nor entropy
+#[cfg(not(miri))] // Miri does not support threads
 fn panic_safe() {
     let prev = panic::take_hook();
     panic::set_hook(Box::new(move |info| {
diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs
index 007283b5f69..acf6b03791f 100644
--- a/src/libcore/tests/slice.rs
+++ b/src/libcore/tests/slice.rs
@@ -1024,22 +1024,31 @@ fn test_rotate_right() {
 
 #[test]
 #[cfg(not(target_arch = "wasm32"))]
-#[cfg(not(miri))] // Miri does not support entropy
 fn sort_unstable() {
     use core::cmp::Ordering::{Equal, Greater, Less};
     use core::slice::heapsort;
     use rand::{FromEntropy, Rng, rngs::SmallRng, seq::SliceRandom};
 
+    #[cfg(not(miri))] // Miri is too slow
+    let large_range = 500..510;
+    #[cfg(not(miri))] // Miri is too slow
+    let rounds = 100;
+
+    #[cfg(miri)]
+    let large_range = 0..0; // empty range
+    #[cfg(miri)]
+    let rounds = 1;
+
     let mut v = [0; 600];
     let mut tmp = [0; 600];
     let mut rng = SmallRng::from_entropy();
 
-    for len in (2..25).chain(500..510) {
+    for len in (2..25).chain(large_range) {
         let v = &mut v[0..len];
         let tmp = &mut tmp[0..len];
 
         for &modulus in &[5, 10, 100, 1000] {
-            for _ in 0..100 {
+            for _ in 0..rounds {
                 for i in 0..len {
                     v[i] = rng.gen::<i32>() % modulus;
                 }
@@ -1095,7 +1104,7 @@ fn sort_unstable() {
 
 #[test]
 #[cfg(not(target_arch = "wasm32"))]
-#[cfg(not(miri))] // Miri does not support entropy
+#[cfg(not(miri))] // Miri is too slow
 fn partition_at_index() {
     use core::cmp::Ordering::{Equal, Greater, Less};
     use rand::rngs::SmallRng;
diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs
index 80fef910cc7..ca5feaee12e 100644
--- a/src/librustc/mir/interpret/allocation.rs
+++ b/src/librustc/mir/interpret/allocation.rs
@@ -45,12 +45,10 @@ pub struct Allocation<Tag=(),Extra=()> {
 }
 
 
-pub trait AllocationExtra<Tag, MemoryExtra>: ::std::fmt::Debug + Clone {
-    /// Hook to initialize the extra data when an allocation gets created.
-    fn memory_allocated(
-        _size: Size,
-        _memory_extra: &MemoryExtra
-    ) -> Self;
+pub trait AllocationExtra<Tag>: ::std::fmt::Debug + Clone {
+    // There is no constructor in here because the constructor's type depends
+    // on `MemoryKind`, and making things sufficiently generic leads to painful
+    // inference failure.
 
     /// Hook for performing extra checks on a memory read access.
     ///
@@ -88,15 +86,8 @@ pub trait AllocationExtra<Tag, MemoryExtra>: ::std::fmt::Debug + Clone {
     }
 }
 
-impl AllocationExtra<(), ()> for () {
-    #[inline(always)]
-    fn memory_allocated(
-        _size: Size,
-        _memory_extra: &()
-    ) -> Self {
-        ()
-    }
-}
+// For Tag=() and no extra state, we have is a trivial implementation.
+impl AllocationExtra<()> for () { }
 
 impl<Tag, Extra> Allocation<Tag, Extra> {
     /// Creates a read-only allocation initialized by the given bytes
@@ -159,7 +150,7 @@ impl<'tcx, Tag, Extra> Allocation<Tag, Extra> {
 }
 
 /// Byte accessors
-impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
+impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
     /// The last argument controls whether we error out when there are undefined
     /// or pointer bytes. You should never call this, call `get_bytes` or
     /// `get_bytes_with_undef_and_ptr` instead,
@@ -167,15 +158,13 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
     /// This function also guarantees that the resulting pointer will remain stable
     /// even when new allocations are pushed to the `HashMap`. `copy_repeatedly` relies
     /// on that.
-    fn get_bytes_internal<MemoryExtra>(
+    fn get_bytes_internal(
         &self,
         cx: &impl HasDataLayout,
         ptr: Pointer<Tag>,
         size: Size,
         check_defined_and_ptr: bool,
     ) -> EvalResult<'tcx, &[u8]>
-        // FIXME: Working around https://github.com/rust-lang/rust/issues/56209
-        where Extra: AllocationExtra<Tag, MemoryExtra>
     {
         self.check_bounds(cx, ptr, size)?;
 
@@ -196,14 +185,12 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
     }
 
     #[inline]
-    pub fn get_bytes<MemoryExtra>(
+    pub fn get_bytes(
         &self,
         cx: &impl HasDataLayout,
         ptr: Pointer<Tag>,
         size: Size,
     ) -> EvalResult<'tcx, &[u8]>
-        // FIXME: Working around https://github.com/rust-lang/rust/issues/56209
-        where Extra: AllocationExtra<Tag, MemoryExtra>
     {
         self.get_bytes_internal(cx, ptr, size, true)
     }
@@ -211,28 +198,24 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
     /// It is the caller's responsibility to handle undefined and pointer bytes.
     /// However, this still checks that there are no relocations on the *edges*.
     #[inline]
-    pub fn get_bytes_with_undef_and_ptr<MemoryExtra>(
+    pub fn get_bytes_with_undef_and_ptr(
         &self,
         cx: &impl HasDataLayout,
         ptr: Pointer<Tag>,
         size: Size,
     ) -> EvalResult<'tcx, &[u8]>
-        // FIXME: Working around https://github.com/rust-lang/rust/issues/56209
-        where Extra: AllocationExtra<Tag, MemoryExtra>
     {
         self.get_bytes_internal(cx, ptr, size, false)
     }
 
     /// Just calling this already marks everything as defined and removes relocations,
     /// so be sure to actually put data there!
-    pub fn get_bytes_mut<MemoryExtra>(
+    pub fn get_bytes_mut(
         &mut self,
         cx: &impl HasDataLayout,
         ptr: Pointer<Tag>,
         size: Size,
     ) -> EvalResult<'tcx, &mut [u8]>
-        // FIXME: Working around https://github.com/rust-lang/rust/issues/56209
-        where Extra: AllocationExtra<Tag, MemoryExtra>
     {
         assert_ne!(size.bytes(), 0, "0-sized accesses should never even get a `Pointer`");
         self.check_bounds(cx, ptr, size)?;
@@ -250,16 +233,14 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
 }
 
 /// Reading and writing
-impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
+impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
     /// Reads bytes until a `0` is encountered. Will error if the end of the allocation is reached
     /// before a `0` is found.
-    pub fn read_c_str<MemoryExtra>(
+    pub fn read_c_str(
         &self,
         cx: &impl HasDataLayout,
         ptr: Pointer<Tag>,
     ) -> EvalResult<'tcx, &[u8]>
-        // FIXME: Working around https://github.com/rust-lang/rust/issues/56209
-        where Extra: AllocationExtra<Tag, MemoryExtra>
     {
         assert_eq!(ptr.offset.bytes() as usize as u64, ptr.offset.bytes());
         let offset = ptr.offset.bytes() as usize;
@@ -278,15 +259,13 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
     /// Validates that `ptr.offset` and `ptr.offset + size` do not point to the middle of a
     /// relocation. If `allow_ptr_and_undef` is `false`, also enforces that the memory in the
     /// given range contains neither relocations nor undef bytes.
-    pub fn check_bytes<MemoryExtra>(
+    pub fn check_bytes(
         &self,
         cx: &impl HasDataLayout,
         ptr: Pointer<Tag>,
         size: Size,
         allow_ptr_and_undef: bool,
     ) -> EvalResult<'tcx>
-        // FIXME: Working around https://github.com/rust-lang/rust/issues/56209
-        where Extra: AllocationExtra<Tag, MemoryExtra>
     {
         // Check bounds and relocations on the edges
         self.get_bytes_with_undef_and_ptr(cx, ptr, size)?;
@@ -301,14 +280,12 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
     /// Writes `src` to the memory starting at `ptr.offset`.
     ///
     /// Will do bounds checks on the allocation.
-    pub fn write_bytes<MemoryExtra>(
+    pub fn write_bytes(
         &mut self,
         cx: &impl HasDataLayout,
         ptr: Pointer<Tag>,
         src: &[u8],
     ) -> EvalResult<'tcx>
-        // FIXME: Working around https://github.com/rust-lang/rust/issues/56209
-        where Extra: AllocationExtra<Tag, MemoryExtra>
     {
         let bytes = self.get_bytes_mut(cx, ptr, Size::from_bytes(src.len() as u64))?;
         bytes.clone_from_slice(src);
@@ -316,15 +293,13 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
     }
 
     /// Sets `count` bytes starting at `ptr.offset` with `val`. Basically `memset`.
-    pub fn write_repeat<MemoryExtra>(
+    pub fn write_repeat(
         &mut self,
         cx: &impl HasDataLayout,
         ptr: Pointer<Tag>,
         val: u8,
         count: Size
     ) -> EvalResult<'tcx>
-        // FIXME: Working around https://github.com/rust-lang/rust/issues/56209
-        where Extra: AllocationExtra<Tag, MemoryExtra>
     {
         let bytes = self.get_bytes_mut(cx, ptr, count)?;
         for b in bytes {
@@ -341,14 +316,12 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
     ///   being valid for ZSTs
     ///
     /// Note: This function does not do *any* alignment checks, you need to do these before calling
-    pub fn read_scalar<MemoryExtra>(
+    pub fn read_scalar(
         &self,
         cx: &impl HasDataLayout,
         ptr: Pointer<Tag>,
         size: Size
     ) -> EvalResult<'tcx, ScalarMaybeUndef<Tag>>
-        // FIXME: Working around https://github.com/rust-lang/rust/issues/56209
-        where Extra: AllocationExtra<Tag, MemoryExtra>
     {
         // get_bytes_unchecked tests relocation edges
         let bytes = self.get_bytes_with_undef_and_ptr(cx, ptr, size)?;
@@ -379,13 +352,11 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
     }
 
     /// Note: This function does not do *any* alignment checks, you need to do these before calling
-    pub fn read_ptr_sized<MemoryExtra>(
+    pub fn read_ptr_sized(
         &self,
         cx: &impl HasDataLayout,
         ptr: Pointer<Tag>,
     ) -> EvalResult<'tcx, ScalarMaybeUndef<Tag>>
-        // FIXME: Working around https://github.com/rust-lang/rust/issues/56209
-        where Extra: AllocationExtra<Tag, MemoryExtra>
     {
         self.read_scalar(cx, ptr, cx.data_layout().pointer_size)
     }
@@ -398,15 +369,13 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
     ///   being valid for ZSTs
     ///
     /// Note: This function does not do *any* alignment checks, you need to do these before calling
-    pub fn write_scalar<MemoryExtra>(
+    pub fn write_scalar(
         &mut self,
         cx: &impl HasDataLayout,
         ptr: Pointer<Tag>,
         val: ScalarMaybeUndef<Tag>,
         type_size: Size,
     ) -> EvalResult<'tcx>
-        // FIXME: Working around https://github.com/rust-lang/rust/issues/56209
-        where Extra: AllocationExtra<Tag, MemoryExtra>
     {
         let val = match val {
             ScalarMaybeUndef::Scalar(scalar) => scalar,
@@ -446,14 +415,12 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
     }
 
     /// Note: This function does not do *any* alignment checks, you need to do these before calling
-    pub fn write_ptr_sized<MemoryExtra>(
+    pub fn write_ptr_sized(
         &mut self,
         cx: &impl HasDataLayout,
         ptr: Pointer<Tag>,
         val: ScalarMaybeUndef<Tag>
     ) -> EvalResult<'tcx>
-        // FIXME: Working around https://github.com/rust-lang/rust/issues/56209
-        where Extra: AllocationExtra<Tag, MemoryExtra>
     {
         let ptr_size = cx.data_layout().pointer_size;
         self.write_scalar(cx, ptr.into(), val, ptr_size)
diff --git a/src/librustc/mir/interpret/pointer.rs b/src/librustc/mir/interpret/pointer.rs
index 9216cb494ce..75e0f704a58 100644
--- a/src/librustc/mir/interpret/pointer.rs
+++ b/src/librustc/mir/interpret/pointer.rs
@@ -95,10 +95,16 @@ impl<'tcx> Pointer<()> {
     }
 
     #[inline(always)]
+    pub fn with_tag<Tag>(self, tag: Tag) -> Pointer<Tag>
+    {
+        Pointer::new_with_tag(self.alloc_id, self.offset, tag)
+    }
+
+    #[inline(always)]
     pub fn with_default_tag<Tag>(self) -> Pointer<Tag>
         where Tag: Default
     {
-        Pointer::new_with_tag(self.alloc_id, self.offset, Default::default())
+        self.with_tag(Tag::default())
     }
 }
 
diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs
index 7b47c02de1b..18c82ecd38e 100644
--- a/src/librustc/mir/interpret/value.rs
+++ b/src/librustc/mir/interpret/value.rs
@@ -119,14 +119,19 @@ impl<Tag> fmt::Display for Scalar<Tag> {
 
 impl<'tcx> Scalar<()> {
     #[inline]
-    pub fn with_default_tag<Tag>(self) -> Scalar<Tag>
-        where Tag: Default
-    {
+    pub fn with_tag<Tag>(self, new_tag: Tag) -> Scalar<Tag> {
         match self {
-            Scalar::Ptr(ptr) => Scalar::Ptr(ptr.with_default_tag()),
+            Scalar::Ptr(ptr) => Scalar::Ptr(ptr.with_tag(new_tag)),
             Scalar::Bits { bits, size } => Scalar::Bits { bits, size },
         }
     }
+
+    #[inline(always)]
+    pub fn with_default_tag<Tag>(self) -> Scalar<Tag>
+        where Tag: Default
+    {
+        self.with_tag(Tag::default())
+    }
 }
 
 impl<'tcx, Tag> Scalar<Tag> {
@@ -139,14 +144,6 @@ impl<'tcx, Tag> Scalar<Tag> {
     }
 
     #[inline]
-    pub fn with_tag(self, new_tag: Tag) -> Self {
-        match self {
-            Scalar::Ptr(ptr) => Scalar::Ptr(Pointer { tag: new_tag, ..ptr }),
-            Scalar::Bits { bits, size } => Scalar::Bits { bits, size },
-        }
-    }
-
-    #[inline]
     pub fn ptr_null(cx: &impl HasDataLayout) -> Self {
         Scalar::Bits {
             bits: 0,
@@ -434,14 +431,19 @@ impl<Tag> fmt::Display for ScalarMaybeUndef<Tag> {
 
 impl<'tcx> ScalarMaybeUndef<()> {
     #[inline]
-    pub fn with_default_tag<Tag>(self) -> ScalarMaybeUndef<Tag>
-        where Tag: Default
-    {
+    pub fn with_tag<Tag>(self, new_tag: Tag) -> ScalarMaybeUndef<Tag> {
         match self {
-            ScalarMaybeUndef::Scalar(s) => ScalarMaybeUndef::Scalar(s.with_default_tag()),
+            ScalarMaybeUndef::Scalar(s) => ScalarMaybeUndef::Scalar(s.with_tag(new_tag)),
             ScalarMaybeUndef::Undef => ScalarMaybeUndef::Undef,
         }
     }
+
+    #[inline(always)]
+    pub fn with_default_tag<Tag>(self) -> ScalarMaybeUndef<Tag>
+        where Tag: Default
+    {
+        self.with_tag(Tag::default())
+    }
 }
 
 impl<'tcx, Tag> ScalarMaybeUndef<Tag> {
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index d3a734cbc6e..dc1ceaf69f0 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -19,6 +19,7 @@ use syntax::parse::token;
 use syntax::parse;
 use syntax::symbol::Symbol;
 use syntax::feature_gate::UnstableFeatures;
+use errors::emitter::HumanReadableErrorType;
 
 use errors::{ColorConfig, FatalError, Handler};
 
@@ -219,14 +220,18 @@ impl OutputType {
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum ErrorOutputType {
-    HumanReadable(ColorConfig),
-    Json(bool),
-    Short(ColorConfig),
+    HumanReadable(HumanReadableErrorType),
+    Json {
+        /// Render the json in a human readable way (with indents and newlines)
+        pretty: bool,
+        /// The way the `rendered` field is created
+        json_rendered: HumanReadableErrorType,
+    },
 }
 
 impl Default for ErrorOutputType {
     fn default() -> ErrorOutputType {
-        ErrorOutputType::HumanReadable(ColorConfig::Auto)
+        ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
     }
 }
 
@@ -1372,6 +1377,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
         "print some statistics about AST and HIR"),
     always_encode_mir: bool = (false, parse_bool, [TRACKED],
         "encode MIR of all functions into the crate metadata"),
+    json_rendered: Option<String> = (None, parse_opt_string, [UNTRACKED],
+        "describes how to render the `rendered` field of json diagnostics"),
     unleash_the_miri_inside_of_you: bool = (false, parse_bool, [TRACKED],
         "take the breaks off const evaluation. NOTE: this is unsound"),
     osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
@@ -1825,6 +1832,12 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
             "How errors and other messages are produced",
             "human|json|short",
         ),
+        opt::opt(
+            "",
+            "json-rendered",
+            "Choose `rendered` field of json diagnostics render scheme",
+            "plain|termcolor",
+        ),
         opt::opt_s(
             "",
             "color",
@@ -1965,6 +1978,17 @@ pub fn build_session_options_and_crate_config(
         )
     }
 
+    let json_rendered = matches.opt_str("json-rendered").and_then(|s| match s.as_str() {
+        "plain" => None,
+        "termcolor" => Some(HumanReadableErrorType::Default(ColorConfig::Always)),
+        _ => early_error(
+            ErrorOutputType::default(),
+            &format!(
+                "argument for --json-rendered must be `plain` or `termcolor` (instead was `{}`)",
+                s,
+            ),
+        ),
+    }).unwrap_or(HumanReadableErrorType::Default(ColorConfig::Never));
 
     // We need the opts_present check because the driver will send us Matches
     // with only stable options if no unstable options are used. Since error-format
@@ -1972,14 +1996,14 @@ pub fn build_session_options_and_crate_config(
     // opt_present because the latter will panic.
     let error_format = if matches.opts_present(&["error-format".to_owned()]) {
         match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
-            Some("human") => ErrorOutputType::HumanReadable(color),
-            Some("json") => ErrorOutputType::Json(false),
-            Some("pretty-json") => ErrorOutputType::Json(true),
-            Some("short") => ErrorOutputType::Short(color),
-            None => ErrorOutputType::HumanReadable(color),
+            None |
+            Some("human") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
+            Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
+            Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
+            Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
 
             Some(arg) => early_error(
-                ErrorOutputType::HumanReadable(color),
+                ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
                 &format!(
                     "argument for --error-format must be `human`, `json` or \
                      `short` (instead was `{}`)",
@@ -1988,7 +2012,7 @@ pub fn build_session_options_and_crate_config(
             ),
         }
     } else {
-        ErrorOutputType::HumanReadable(color)
+        ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
     };
 
     let unparsed_crate_types = matches.opt_strs("crate-type");
@@ -2000,11 +2024,16 @@ pub fn build_session_options_and_crate_config(
 
     let mut debugging_opts = build_debugging_options(matches, error_format);
 
-    if !debugging_opts.unstable_options && error_format == ErrorOutputType::Json(true) {
-        early_error(
-            ErrorOutputType::Json(false),
-            "--error-format=pretty-json is unstable",
-        );
+    if !debugging_opts.unstable_options {
+        if matches.opt_str("json-rendered").is_some() {
+            early_error(error_format, "`--json-rendered=x` is unstable");
+        }
+        if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
+            early_error(
+                ErrorOutputType::Json { pretty: false, json_rendered },
+                "--error-format=pretty-json is unstable",
+            );
+        }
     }
 
     if debugging_opts.pgo_gen.enabled() && !debugging_opts.pgo_use.is_empty() {
@@ -2928,50 +2957,55 @@ mod tests {
         let mut v3 = Options::default();
         let mut v4 = Options::default();
 
+        const JSON: super::ErrorOutputType = super::ErrorOutputType::Json {
+            pretty: false,
+            json_rendered: super::HumanReadableErrorType::Default(super::ColorConfig::Never),
+        };
+
         // Reference
         v1.search_paths
-            .push(SearchPath::from_cli_opt("native=abc", super::ErrorOutputType::Json(false)));
+            .push(SearchPath::from_cli_opt("native=abc", JSON));
         v1.search_paths
-            .push(SearchPath::from_cli_opt("crate=def", super::ErrorOutputType::Json(false)));
+            .push(SearchPath::from_cli_opt("crate=def", JSON));
         v1.search_paths
-            .push(SearchPath::from_cli_opt("dependency=ghi", super::ErrorOutputType::Json(false)));
+            .push(SearchPath::from_cli_opt("dependency=ghi", JSON));
         v1.search_paths
-            .push(SearchPath::from_cli_opt("framework=jkl", super::ErrorOutputType::Json(false)));
+            .push(SearchPath::from_cli_opt("framework=jkl", JSON));
         v1.search_paths
-            .push(SearchPath::from_cli_opt("all=mno", super::ErrorOutputType::Json(false)));
+            .push(SearchPath::from_cli_opt("all=mno", JSON));
 
         v2.search_paths
-            .push(SearchPath::from_cli_opt("native=abc", super::ErrorOutputType::Json(false)));
+            .push(SearchPath::from_cli_opt("native=abc", JSON));
         v2.search_paths
-            .push(SearchPath::from_cli_opt("dependency=ghi", super::ErrorOutputType::Json(false)));
+            .push(SearchPath::from_cli_opt("dependency=ghi", JSON));
         v2.search_paths
-            .push(SearchPath::from_cli_opt("crate=def", super::ErrorOutputType::Json(false)));
+            .push(SearchPath::from_cli_opt("crate=def", JSON));
         v2.search_paths
-            .push(SearchPath::from_cli_opt("framework=jkl", super::ErrorOutputType::Json(false)));
+            .push(SearchPath::from_cli_opt("framework=jkl", JSON));
         v2.search_paths
-            .push(SearchPath::from_cli_opt("all=mno", super::ErrorOutputType::Json(false)));
+            .push(SearchPath::from_cli_opt("all=mno", JSON));
 
         v3.search_paths
-            .push(SearchPath::from_cli_opt("crate=def", super::ErrorOutputType::Json(false)));
+            .push(SearchPath::from_cli_opt("crate=def", JSON));
         v3.search_paths
-            .push(SearchPath::from_cli_opt("framework=jkl", super::ErrorOutputType::Json(false)));
+            .push(SearchPath::from_cli_opt("framework=jkl", JSON));
         v3.search_paths
-            .push(SearchPath::from_cli_opt("native=abc", super::ErrorOutputType::Json(false)));
+            .push(SearchPath::from_cli_opt("native=abc", JSON));
         v3.search_paths
-            .push(SearchPath::from_cli_opt("dependency=ghi", super::ErrorOutputType::Json(false)));
+            .push(SearchPath::from_cli_opt("dependency=ghi", JSON));
         v3.search_paths
-            .push(SearchPath::from_cli_opt("all=mno", super::ErrorOutputType::Json(false)));
+            .push(SearchPath::from_cli_opt("all=mno", JSON));
 
         v4.search_paths
-            .push(SearchPath::from_cli_opt("all=mno", super::ErrorOutputType::Json(false)));
+            .push(SearchPath::from_cli_opt("all=mno", JSON));
         v4.search_paths
-            .push(SearchPath::from_cli_opt("native=abc", super::ErrorOutputType::Json(false)));
+            .push(SearchPath::from_cli_opt("native=abc", JSON));
         v4.search_paths
-            .push(SearchPath::from_cli_opt("crate=def", super::ErrorOutputType::Json(false)));
+            .push(SearchPath::from_cli_opt("crate=def", JSON));
         v4.search_paths
-            .push(SearchPath::from_cli_opt("dependency=ghi", super::ErrorOutputType::Json(false)));
+            .push(SearchPath::from_cli_opt("dependency=ghi", JSON));
         v4.search_paths
-            .push(SearchPath::from_cli_opt("framework=jkl", super::ErrorOutputType::Json(false)));
+            .push(SearchPath::from_cli_opt("framework=jkl", JSON));
 
         assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
         assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash());
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index a1966c02683..eed516a4381 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -1033,39 +1033,42 @@ fn default_emitter(
     emitter_dest: Option<Box<dyn Write + Send>>,
 ) -> Box<dyn Emitter + sync::Send> {
     match (sopts.error_format, emitter_dest) {
-        (config::ErrorOutputType::HumanReadable(color_config), None) => Box::new(
-            EmitterWriter::stderr(
-                color_config,
-                Some(source_map.clone()),
-                false,
-                sopts.debugging_opts.teach,
-            ).ui_testing(sopts.debugging_opts.ui_testing),
-        ),
-        (config::ErrorOutputType::HumanReadable(_), Some(dst)) => Box::new(
-            EmitterWriter::new(dst, Some(source_map.clone()), false, false)
-                .ui_testing(sopts.debugging_opts.ui_testing),
-        ),
-        (config::ErrorOutputType::Json(pretty), None) => Box::new(
+        (config::ErrorOutputType::HumanReadable(kind), dst) => {
+            let (short, color_config) = kind.unzip();
+            let emitter = match dst {
+                None => EmitterWriter::stderr(
+                    color_config,
+                    Some(source_map.clone()),
+                    short,
+                    sopts.debugging_opts.teach,
+                ),
+                Some(dst) => EmitterWriter::new(
+                    dst,
+                    Some(source_map.clone()),
+                    short,
+                    false, // no teach messages when writing to a buffer
+                    false, // no colors when writing to a buffer
+                ),
+            };
+            Box::new(emitter.ui_testing(sopts.debugging_opts.ui_testing))
+        },
+        (config::ErrorOutputType::Json { pretty, json_rendered }, None) => Box::new(
             JsonEmitter::stderr(
                 Some(registry),
                 source_map.clone(),
                 pretty,
+                json_rendered,
             ).ui_testing(sopts.debugging_opts.ui_testing),
         ),
-        (config::ErrorOutputType::Json(pretty), Some(dst)) => Box::new(
+        (config::ErrorOutputType::Json { pretty, json_rendered }, Some(dst)) => Box::new(
             JsonEmitter::new(
                 dst,
                 Some(registry),
                 source_map.clone(),
                 pretty,
+                json_rendered,
             ).ui_testing(sopts.debugging_opts.ui_testing),
         ),
-        (config::ErrorOutputType::Short(color_config), None) => Box::new(
-            EmitterWriter::stderr(color_config, Some(source_map.clone()), true, false),
-        ),
-        (config::ErrorOutputType::Short(_), Some(dst)) => {
-            Box::new(EmitterWriter::new(dst, Some(source_map.clone()), true, false))
-        }
     }
 }
 
@@ -1322,13 +1325,12 @@ pub enum IncrCompSession {
 
 pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! {
     let emitter: Box<dyn Emitter + sync::Send> = match output {
-        config::ErrorOutputType::HumanReadable(color_config) => {
-            Box::new(EmitterWriter::stderr(color_config, None, false, false))
-        }
-        config::ErrorOutputType::Json(pretty) => Box::new(JsonEmitter::basic(pretty)),
-        config::ErrorOutputType::Short(color_config) => {
-            Box::new(EmitterWriter::stderr(color_config, None, true, false))
+        config::ErrorOutputType::HumanReadable(kind) => {
+            let (short, color_config) = kind.unzip();
+            Box::new(EmitterWriter::stderr(color_config, None, short, false))
         }
+        config::ErrorOutputType::Json { pretty, json_rendered } =>
+            Box::new(JsonEmitter::basic(pretty, json_rendered)),
     };
     let handler = errors::Handler::with_emitter(true, None, emitter);
     handler.emit(&MultiSpan::new(), msg, errors::Level::Fatal);
@@ -1337,13 +1339,12 @@ pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! {
 
 pub fn early_warn(output: config::ErrorOutputType, msg: &str) {
     let emitter: Box<dyn Emitter + sync::Send> = match output {
-        config::ErrorOutputType::HumanReadable(color_config) => {
-            Box::new(EmitterWriter::stderr(color_config, None, false, false))
-        }
-        config::ErrorOutputType::Json(pretty) => Box::new(JsonEmitter::basic(pretty)),
-        config::ErrorOutputType::Short(color_config) => {
-            Box::new(EmitterWriter::stderr(color_config, None, true, false))
+        config::ErrorOutputType::HumanReadable(kind) => {
+            let (short, color_config) = kind.unzip();
+            Box::new(EmitterWriter::stderr(color_config, None, short, false))
         }
+        config::ErrorOutputType::Json { pretty, json_rendered } =>
+            Box::new(JsonEmitter::basic(pretty, json_rendered)),
     };
     let handler = errors::Handler::with_emitter(true, None, emitter);
     handler.emit(&MultiSpan::new(), msg, errors::Level::Warning);
diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs
index ee2a1b69cbd..a1472479afa 100644
--- a/src/librustc_errors/emitter.rs
+++ b/src/librustc_errors/emitter.rs
@@ -16,9 +16,35 @@ use std::borrow::Cow;
 use std::io::prelude::*;
 use std::io;
 use std::cmp::{min, Reverse};
-use termcolor::{StandardStream, ColorChoice, ColorSpec, BufferWriter};
+use termcolor::{StandardStream, ColorChoice, ColorSpec, BufferWriter, Ansi};
 use termcolor::{WriteColor, Color, Buffer};
 
+/// Describes the way the content of the `rendered` field of the json output is generated
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum HumanReadableErrorType {
+    Default(ColorConfig),
+    Short(ColorConfig),
+}
+
+impl HumanReadableErrorType {
+    /// Returns a (`short`, `color`) tuple
+    pub fn unzip(self) -> (bool, ColorConfig) {
+        match self {
+            HumanReadableErrorType::Default(cc) => (false, cc),
+            HumanReadableErrorType::Short(cc) => (true, cc),
+        }
+    }
+    pub fn new_emitter(
+        self,
+        dst: Box<dyn Write + Send>,
+        source_map: Option<Lrc<SourceMapperDyn>>,
+        teach: bool,
+    ) -> EmitterWriter {
+        let (short, color_config) = self.unzip();
+        EmitterWriter::new(dst, source_map, short, teach, color_config.suggests_using_colors())
+    }
+}
+
 const ANONYMIZED_LINE_NUM: &str = "LL";
 
 /// Emitter trait for emitting errors.
@@ -104,8 +130,8 @@ pub enum ColorConfig {
 }
 
 impl ColorConfig {
-    fn to_color_choice(&self) -> ColorChoice {
-        match *self {
+    fn to_color_choice(self) -> ColorChoice {
+        match self {
             ColorConfig::Always => {
                 if atty::is(atty::Stream::Stderr) {
                     ColorChoice::Always
@@ -120,6 +146,14 @@ impl ColorConfig {
             ColorConfig::Auto => ColorChoice::Never,
         }
     }
+    fn suggests_using_colors(self) -> bool {
+        match self {
+            | ColorConfig::Always
+            | ColorConfig::Auto
+            => true,
+            ColorConfig::Never => false,
+        }
+    }
 }
 
 pub struct EmitterWriter {
@@ -152,13 +186,15 @@ impl EmitterWriter {
         }
     }
 
-    pub fn new(dst: Box<dyn Write + Send>,
-               source_map: Option<Lrc<SourceMapperDyn>>,
-               short_message: bool,
-               teach: bool)
-               -> EmitterWriter {
+    pub fn new(
+        dst: Box<dyn Write + Send>,
+        source_map: Option<Lrc<SourceMapperDyn>>,
+        short_message: bool,
+        teach: bool,
+        colored: bool,
+    ) -> EmitterWriter {
         EmitterWriter {
-            dst: Raw(dst),
+            dst: Raw(dst, colored),
             sm: source_map,
             short_message,
             teach,
@@ -1538,13 +1574,15 @@ fn emit_to_destination(rendered_buffer: &[Vec<StyledString>],
 pub enum Destination {
     Terminal(StandardStream),
     Buffered(BufferWriter),
-    Raw(Box<dyn Write + Send>),
+    // The bool denotes whether we should be emitting ansi color codes or not
+    Raw(Box<(dyn Write + Send)>, bool),
 }
 
 pub enum WritableDst<'a> {
     Terminal(&'a mut StandardStream),
     Buffered(&'a mut BufferWriter, Buffer),
-    Raw(&'a mut Box<dyn Write + Send>),
+    Raw(&'a mut (dyn Write + Send)),
+    ColoredRaw(Ansi<&'a mut (dyn Write + Send)>),
 }
 
 impl Destination {
@@ -1570,7 +1608,8 @@ impl Destination {
                 let buf = t.buffer();
                 WritableDst::Buffered(t, buf)
             }
-            Destination::Raw(ref mut t) => WritableDst::Raw(t),
+            Destination::Raw(ref mut t, false) => WritableDst::Raw(t),
+            Destination::Raw(ref mut t, true) => WritableDst::ColoredRaw(Ansi::new(t)),
         }
     }
 }
@@ -1628,6 +1667,7 @@ impl<'a> WritableDst<'a> {
         match *self {
             WritableDst::Terminal(ref mut t) => t.set_color(color),
             WritableDst::Buffered(_, ref mut t) => t.set_color(color),
+            WritableDst::ColoredRaw(ref mut t) => t.set_color(color),
             WritableDst::Raw(_) => Ok(())
         }
     }
@@ -1636,6 +1676,7 @@ impl<'a> WritableDst<'a> {
         match *self {
             WritableDst::Terminal(ref mut t) => t.reset(),
             WritableDst::Buffered(_, ref mut t) => t.reset(),
+            WritableDst::ColoredRaw(ref mut t) => t.reset(),
             WritableDst::Raw(_) => Ok(()),
         }
     }
@@ -1647,6 +1688,7 @@ impl<'a> Write for WritableDst<'a> {
             WritableDst::Terminal(ref mut t) => t.write(bytes),
             WritableDst::Buffered(_, ref mut buf) => buf.write(bytes),
             WritableDst::Raw(ref mut w) => w.write(bytes),
+            WritableDst::ColoredRaw(ref mut t) => t.write(bytes),
         }
     }
 
@@ -1655,6 +1697,7 @@ impl<'a> Write for WritableDst<'a> {
             WritableDst::Terminal(ref mut t) => t.flush(),
             WritableDst::Buffered(_, ref mut buf) => buf.flush(),
             WritableDst::Raw(ref mut w) => w.flush(),
+            WritableDst::ColoredRaw(ref mut w) => w.flush(),
         }
     }
 }
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index 4c8ab361e04..09c50d4f81f 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -11,7 +11,7 @@ use rustc::hir::def::Def;
 use rustc::mir::interpret::{ConstEvalErr, ErrorHandled};
 use rustc::mir;
 use rustc::ty::{self, TyCtxt, query::TyCtxtAt};
-use rustc::ty::layout::{self, LayoutOf, VariantIdx};
+use rustc::ty::layout::{self, LayoutOf, VariantIdx, Size};
 use rustc::ty::subst::Subst;
 use rustc::traits::Reveal;
 use rustc::util::common::ErrorReported;
@@ -21,7 +21,7 @@ use syntax::ast::Mutability;
 use syntax::source_map::{Span, DUMMY_SP};
 
 use crate::interpret::{self,
-    PlaceTy, MPlaceTy, MemPlace, OpTy, ImmTy, Immediate, Scalar, Pointer,
+    PlaceTy, MPlaceTy, MemPlace, OpTy, ImmTy, Immediate, Scalar,
     RawConst, ConstValue,
     EvalResult, EvalError, InterpError, GlobalId, InterpretCx, StackPopCleanup,
     Allocation, AllocId, MemoryKind,
@@ -406,6 +406,15 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
         Cow::Borrowed(alloc)
     }
 
+    #[inline(always)]
+    fn new_allocation(
+        _size: Size,
+        _extra: &Self::MemoryExtra,
+        _kind: MemoryKind<!>,
+    ) -> (Self::AllocExtra, Self::PointerTag) {
+        ((), ())
+    }
+
     fn box_alloc(
         _ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>,
         _dest: PlaceTy<'tcx>,
@@ -440,15 +449,6 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
     }
 
     #[inline(always)]
-    fn tag_new_allocation(
-        _ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>,
-        ptr: Pointer,
-        _kind: MemoryKind<Self::MemoryKinds>,
-    ) -> Pointer {
-        ptr
-    }
-
-    #[inline(always)]
     fn stack_push(
         _ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>,
     ) -> EvalResult<'tcx> {
diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs
index 09d403ab243..288ffbf3cd6 100644
--- a/src/librustc_mir/interpret/machine.rs
+++ b/src/librustc_mir/interpret/machine.rs
@@ -7,11 +7,11 @@ use std::hash::Hash;
 
 use rustc::hir::{self, def_id::DefId};
 use rustc::mir;
-use rustc::ty::{self, query::TyCtxtAt};
+use rustc::ty::{self, query::TyCtxtAt, layout::Size};
 
 use super::{
     Allocation, AllocId, EvalResult, Scalar, AllocationExtra,
-    InterpretCx, PlaceTy, MPlaceTy, OpTy, ImmTy, Pointer, MemoryKind,
+    InterpretCx, PlaceTy, MPlaceTy, OpTy, ImmTy, MemoryKind,
 };
 
 /// Whether this kind of memory is allowed to leak
@@ -76,7 +76,7 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
     type MemoryExtra: Default;
 
     /// Extra data stored in every allocation.
-    type AllocExtra: AllocationExtra<Self::PointerTag, Self::MemoryExtra> + 'static;
+    type AllocExtra: AllocationExtra<Self::PointerTag> + 'static;
 
     /// Memory's allocation map
     type MemoryMap:
@@ -139,18 +139,6 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
         memory_extra: &Self::MemoryExtra,
     ) -> EvalResult<'tcx, Cow<'tcx, Allocation<Self::PointerTag, Self::AllocExtra>>>;
 
-    /// Called to turn an allocation obtained from the `tcx` into one that has
-    /// the right type for this machine.
-    ///
-    /// This should avoid copying if no work has to be done! If this returns an owned
-    /// allocation (because a copy had to be done to add tags or metadata), machine memory will
-    /// cache the result. (This relies on `AllocMap::get_or` being able to add the
-    /// owned allocation to the map even when the map is shared.)
-    fn adjust_static_allocation<'b>(
-        alloc: &'b Allocation,
-        memory_extra: &Self::MemoryExtra,
-    ) -> Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>;
-
     /// Called for all binary operations on integer(-like) types when one operand is a pointer
     /// value, and for the `Offset` operation that is inherently about pointers.
     ///
@@ -168,12 +156,24 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
         dest: PlaceTy<'tcx, Self::PointerTag>,
     ) -> EvalResult<'tcx>;
 
-    /// Adds the tag for a newly allocated pointer.
-    fn tag_new_allocation(
-        ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>,
-        ptr: Pointer,
+    /// Called to turn an allocation obtained from the `tcx` into one that has
+    /// the right type for this machine.
+    ///
+    /// This should avoid copying if no work has to be done! If this returns an owned
+    /// allocation (because a copy had to be done to add tags or metadata), machine memory will
+    /// cache the result. (This relies on `AllocMap::get_or` being able to add the
+    /// owned allocation to the map even when the map is shared.)
+    fn adjust_static_allocation<'b>(
+        alloc: &'b Allocation,
+        memory_extra: &Self::MemoryExtra,
+    ) -> Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>;
+
+    /// Computes the extra state and the tag for a new allocation.
+    fn new_allocation(
+        size: Size,
+        extra: &Self::MemoryExtra,
         kind: MemoryKind<Self::MemoryKinds>,
-    ) -> Pointer<Self::PointerTag>;
+    ) -> (Self::AllocExtra, Self::PointerTag);
 
     /// Executed when evaluating the `*` operator: Following a reference.
     /// This has the chance to adjust the tag. It should not change anything else!
diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index e5d8341dfcf..117bd15399c 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -132,9 +132,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         size: Size,
         align: Align,
         kind: MemoryKind<M::MemoryKinds>,
-    ) -> Pointer {
-        let extra = AllocationExtra::memory_allocated(size, &self.extra);
-        Pointer::from(self.allocate_with(Allocation::undef(size, align, extra), kind))
+    ) -> Pointer<M::PointerTag> {
+        let (extra, tag) = M::new_allocation(size, &self.extra, kind);
+        Pointer::from(self.allocate_with(Allocation::undef(size, align, extra), kind)).with_tag(tag)
     }
 
     pub fn reallocate(
@@ -145,7 +145,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         new_size: Size,
         new_align: Align,
         kind: MemoryKind<M::MemoryKinds>,
-    ) -> EvalResult<'tcx, Pointer> {
+    ) -> EvalResult<'tcx, Pointer<M::PointerTag>> {
         if ptr.offset.bytes() != 0 {
             return err!(ReallocateNonBasePtr);
         }
@@ -156,7 +156,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         self.copy(
             ptr.into(),
             old_align,
-            new_ptr.with_default_tag().into(),
+            new_ptr.into(),
             new_align,
             old_size.min(new_size),
             /*nonoverlapping*/ true,
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index 1ce6d09d7a4..55c1bfb17de 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -31,19 +31,6 @@ pub enum Immediate<Tag=(), Id=AllocId> {
     ScalarPair(ScalarMaybeUndef<Tag, Id>, ScalarMaybeUndef<Tag, Id>),
 }
 
-impl Immediate {
-    #[inline]
-    pub fn with_default_tag<Tag>(self) -> Immediate<Tag>
-        where Tag: Default
-    {
-        match self {
-            Immediate::Scalar(x) => Immediate::Scalar(x.with_default_tag()),
-            Immediate::ScalarPair(x, y) =>
-                Immediate::ScalarPair(x.with_default_tag(), y.with_default_tag()),
-        }
-    }
-}
-
 impl<'tcx, Tag> Immediate<Tag> {
     #[inline]
     pub fn from_scalar(val: Scalar<Tag>) -> Self {
@@ -142,18 +129,6 @@ pub enum Operand<Tag=(), Id=AllocId> {
     Indirect(MemPlace<Tag, Id>),
 }
 
-impl Operand {
-    #[inline]
-    pub fn with_default_tag<Tag>(self) -> Operand<Tag>
-        where Tag: Default
-    {
-        match self {
-            Operand::Immediate(x) => Operand::Immediate(x.with_default_tag()),
-            Operand::Indirect(x) => Operand::Indirect(x.with_default_tag()),
-        }
-    }
-}
-
 impl<Tag> Operand<Tag> {
     #[inline]
     pub fn erase_tag(self) -> Operand
@@ -554,16 +529,17 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
                 // We rely on mutability being set correctly in that allocation to prevent writes
                 // where none should happen -- and for `static mut`, we copy on demand anyway.
                 Operand::Indirect(
-                    MemPlace::from_ptr(ptr, alloc.align)
-                ).with_default_tag()
+                    MemPlace::from_ptr(ptr.with_default_tag(), alloc.align)
+                )
             },
             ConstValue::Slice(a, b) =>
                 Operand::Immediate(Immediate::ScalarPair(
-                    a.into(),
-                    Scalar::from_uint(b, self.tcx.data_layout.pointer_size).into(),
-                )).with_default_tag(),
+                    a.with_default_tag().into(),
+                    Scalar::from_uint(b, self.tcx.data_layout.pointer_size)
+                        .with_default_tag().into(),
+                )),
             ConstValue::Scalar(x) =>
-                Operand::Immediate(Immediate::Scalar(x.into())).with_default_tag(),
+                Operand::Immediate(Immediate::Scalar(x.with_default_tag().into())),
             ConstValue::Unevaluated(def_id, substs) => {
                 let instance = self.resolve(def_id, substs)?;
                 return Ok(OpTy::from(self.const_eval_raw(GlobalId {
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index 32ad5274689..8239337796e 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -83,23 +83,19 @@ impl<'tcx, Tag> From<MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> {
     }
 }
 
-impl MemPlace {
+impl<Tag> MemPlace<Tag> {
+    /// Replace ptr tag, maintain vtable tag (if any)
     #[inline]
-    pub fn with_default_tag<Tag>(self) -> MemPlace<Tag>
-        where Tag: Default
-    {
+    pub fn replace_tag(self, new_tag: Tag) -> Self {
         MemPlace {
-            ptr: self.ptr.with_default_tag(),
+            ptr: self.ptr.erase_tag().with_tag(new_tag),
             align: self.align,
-            meta: self.meta.map(Scalar::with_default_tag),
+            meta: self.meta,
         }
     }
-}
 
-impl<Tag> MemPlace<Tag> {
     #[inline]
-    pub fn erase_tag(self) -> MemPlace
-    {
+    pub fn erase_tag(self) -> MemPlace {
         MemPlace {
             ptr: self.ptr.erase_tag(),
             align: self.align,
@@ -107,16 +103,6 @@ impl<Tag> MemPlace<Tag> {
         }
     }
 
-    #[inline]
-    pub fn with_tag(self, new_tag: Tag) -> Self
-    {
-        MemPlace {
-            ptr: self.ptr.with_tag(new_tag),
-            align: self.align,
-            meta: self.meta,
-        }
-    }
-
     #[inline(always)]
     pub fn from_scalar_ptr(ptr: Scalar<Tag>, align: Align) -> Self {
         MemPlace {
@@ -189,11 +175,11 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> {
         }
     }
 
+    /// Replace ptr tag, maintain vtable tag (if any)
     #[inline]
-    pub fn with_tag(self, new_tag: Tag) -> Self
-    {
+    pub fn replace_tag(self, new_tag: Tag) -> Self {
         MPlaceTy {
-            mplace: self.mplace.with_tag(new_tag),
+            mplace: self.mplace.replace_tag(new_tag),
             layout: self.layout,
         }
     }
@@ -312,7 +298,7 @@ where
     M: Machine<'a, 'mir, 'tcx, PointerTag=Tag>,
     // FIXME: Working around https://github.com/rust-lang/rust/issues/24159
     M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation<Tag, M::AllocExtra>)>,
-    M::AllocExtra: AllocationExtra<Tag, M::MemoryExtra>,
+    M::AllocExtra: AllocationExtra<Tag>,
 {
     /// Take a value, which represents a (thin or fat) reference, and make it a place.
     /// Alignment is just based on the type.  This is the inverse of `MemPlace::to_ref()`.
@@ -943,7 +929,6 @@ where
                         let (size, align) = self.size_and_align_of(meta, local_layout)?
                             .expect("Cannot allocate for non-dyn-sized type");
                         let ptr = self.memory.allocate(size, align, MemoryKind::Stack);
-                        let ptr = M::tag_new_allocation(self, ptr, MemoryKind::Stack);
                         let mplace = MemPlace { ptr: ptr.into(), align, meta };
                         if let Some(value) = old_val {
                             // Preserve old value.
@@ -981,7 +966,6 @@ where
         kind: MemoryKind<M::MemoryKinds>,
     ) -> MPlaceTy<'tcx, M::PointerTag> {
         let ptr = self.memory.allocate(layout.size, layout.align.abi, kind);
-        let ptr = M::tag_new_allocation(self, ptr, kind);
         MPlaceTy::from_aligned_ptr(ptr, layout)
     }
 
diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs
index a451f2afb46..0bed62ccf50 100644
--- a/src/librustc_mir/interpret/traits.rs
+++ b/src/librustc_mir/interpret/traits.rs
@@ -52,7 +52,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
             ptr_size * (3 + methods.len() as u64),
             ptr_align,
             MemoryKind::Vtable,
-        ).with_default_tag();
+        );
         let tcx = &*self.tcx;
 
         let drop = crate::monomorphize::resolve_drop_in_place(*tcx, ty);
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index 87459571b52..7826d3da4fe 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -326,7 +326,12 @@ fn check_terminator(
                     abi::Abi::Rust if tcx.is_min_const_fn(def_id) => {},
                     abi::Abi::Rust => return Err((
                         span,
-                        "can only call other `min_const_fn` within a `min_const_fn`".into(),
+                        format!(
+                            "can only call other `const fn` within a `const fn`, \
+                             but `{:?}` is not stable as `const fn`",
+                            func,
+                        )
+                        .into(),
                     )),
                     abi => return Err((
                         span,
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index a4d2a3be863..769ea3ff7bc 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -3,7 +3,7 @@ use std::fmt;
 use std::path::PathBuf;
 
 use errors;
-use errors::emitter::ColorConfig;
+use errors::emitter::{ColorConfig, HumanReadableErrorType};
 use getopts;
 use rustc::lint::Level;
 use rustc::session::early_error;
@@ -254,12 +254,19 @@ impl Options {
                                       (instead was `{}`)", arg));
             }
         };
+        // FIXME: deduplicate this code from the identical code in librustc/session/config.rs
         let error_format = match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
-            Some("human") => ErrorOutputType::HumanReadable(color),
-            Some("json") => ErrorOutputType::Json(false),
-            Some("pretty-json") => ErrorOutputType::Json(true),
-            Some("short") => ErrorOutputType::Short(color),
-            None => ErrorOutputType::HumanReadable(color),
+            None |
+            Some("human") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
+            Some("json") => ErrorOutputType::Json {
+                pretty: false,
+                json_rendered: HumanReadableErrorType::Default(ColorConfig::Never),
+            },
+            Some("pretty-json") => ErrorOutputType::Json {
+                pretty: true,
+                json_rendered: HumanReadableErrorType::Default(ColorConfig::Never),
+            },
+            Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
             Some(arg) => {
                 early_error(ErrorOutputType::default(),
                             &format!("argument for --error-format must be `human`, `json` or \
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 3cf6b32b07c..c141b474815 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -299,15 +299,18 @@ pub fn new_handler(error_format: ErrorOutputType,
     // stick to the defaults
     let sessopts = Options::default();
     let emitter: Box<dyn Emitter + sync::Send> = match error_format {
-        ErrorOutputType::HumanReadable(color_config) => Box::new(
-            EmitterWriter::stderr(
-                color_config,
-                source_map.map(|cm| cm as _),
-                false,
-                sessopts.debugging_opts.teach,
-            ).ui_testing(ui_testing)
-        ),
-        ErrorOutputType::Json(pretty) => {
+        ErrorOutputType::HumanReadable(kind) => {
+            let (short, color_config) = kind.unzip();
+            Box::new(
+                EmitterWriter::stderr(
+                    color_config,
+                    source_map.map(|cm| cm as _),
+                    short,
+                    sessopts.debugging_opts.teach,
+                ).ui_testing(ui_testing)
+            )
+        },
+        ErrorOutputType::Json { pretty, json_rendered } => {
             let source_map = source_map.unwrap_or_else(
                 || Lrc::new(source_map::SourceMap::new(sessopts.file_path_mapping())));
             Box::new(
@@ -315,16 +318,10 @@ pub fn new_handler(error_format: ErrorOutputType,
                     None,
                     source_map,
                     pretty,
+                    json_rendered,
                 ).ui_testing(ui_testing)
             )
         },
-        ErrorOutputType::Short(color_config) => Box::new(
-            EmitterWriter::stderr(
-                color_config,
-                source_map.map(|cm| cm as _),
-                true,
-                false)
-        ),
     };
 
     errors::Handler::with_emitter_and_flags(
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 0bbc7c5c4b2..abf74158c93 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -381,7 +381,7 @@ pub fn make_test(s: &str,
         // Any errors in parsing should also appear when the doctest is compiled for real, so just
         // send all the errors that libsyntax emits directly into a `Sink` instead of stderr.
         let cm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
-        let emitter = EmitterWriter::new(box io::sink(), None, false, false);
+        let emitter = EmitterWriter::new(box io::sink(), None, false, false, false);
         let handler = Handler::with_emitter(false, None, box emitter);
         let sess = ParseSess::with_span_handler(handler, cm);
 
diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs
index 838dfc62646..c19b408442a 100644
--- a/src/libsyntax/json.rs
+++ b/src/libsyntax/json.rs
@@ -14,7 +14,7 @@ use crate::source_map::{SourceMap, FilePathMapping};
 use errors::registry::Registry;
 use errors::{DiagnosticBuilder, SubDiagnostic, CodeSuggestion, SourceMapper};
 use errors::{DiagnosticId, Applicability};
-use errors::emitter::{Emitter, EmitterWriter};
+use errors::emitter::{Emitter, HumanReadableErrorType};
 
 use syntax_pos::{MacroBacktrace, Span, SpanLabel, MultiSpan};
 use rustc_data_structures::sync::{self, Lrc};
@@ -30,37 +30,46 @@ pub struct JsonEmitter {
     sm: Lrc<dyn SourceMapper + sync::Send + sync::Sync>,
     pretty: bool,
     ui_testing: bool,
+    json_rendered: HumanReadableErrorType,
 }
 
 impl JsonEmitter {
-    pub fn stderr(registry: Option<Registry>,
-                  source_map: Lrc<SourceMap>,
-                  pretty: bool) -> JsonEmitter {
+    pub fn stderr(
+        registry: Option<Registry>,
+        source_map: Lrc<SourceMap>,
+        pretty: bool,
+        json_rendered: HumanReadableErrorType,
+    ) -> JsonEmitter {
         JsonEmitter {
             dst: Box::new(io::stderr()),
             registry,
             sm: source_map,
             pretty,
             ui_testing: false,
+            json_rendered,
         }
     }
 
-    pub fn basic(pretty: bool) -> JsonEmitter {
+    pub fn basic(pretty: bool, json_rendered: HumanReadableErrorType) -> JsonEmitter {
         let file_path_mapping = FilePathMapping::empty();
         JsonEmitter::stderr(None, Lrc::new(SourceMap::new(file_path_mapping)),
-                            pretty)
+                            pretty, json_rendered)
     }
 
-    pub fn new(dst: Box<dyn Write + Send>,
-               registry: Option<Registry>,
-               source_map: Lrc<SourceMap>,
-               pretty: bool) -> JsonEmitter {
+    pub fn new(
+        dst: Box<dyn Write + Send>,
+        registry: Option<Registry>,
+        source_map: Lrc<SourceMap>,
+        pretty: bool,
+        json_rendered: HumanReadableErrorType,
+    ) -> JsonEmitter {
         JsonEmitter {
             dst,
             registry,
             sm: source_map,
             pretty,
             ui_testing: false,
+            json_rendered,
         }
     }
 
@@ -190,7 +199,7 @@ impl Diagnostic {
         }
         let buf = BufWriter::default();
         let output = buf.clone();
-        EmitterWriter::new(Box::new(buf), Some(je.sm.clone()), false, false)
+        je.json_rendered.new_emitter(Box::new(buf), Some(je.sm.clone()), false)
             .ui_testing(je.ui_testing).emit(db);
         let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap();
         let output = String::from_utf8(output).unwrap();
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index 5557e281a66..3b980fafc2f 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -1920,6 +1920,7 @@ mod tests {
         let emitter = errors::emitter::EmitterWriter::new(Box::new(io::sink()),
                                                           Some(sm.clone()),
                                                           false,
+                                                          false,
                                                           false);
         ParseSess {
             span_diagnostic: errors::Handler::with_emitter(true, None, Box::new(emitter)),
diff --git a/src/libsyntax/test_snippet.rs b/src/libsyntax/test_snippet.rs
index 86910ffd894..cba429068fd 100644
--- a/src/libsyntax/test_snippet.rs
+++ b/src/libsyntax/test_snippet.rs
@@ -57,6 +57,7 @@ fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &
         let emitter = EmitterWriter::new(Box::new(Shared { data: output.clone() }),
                                         Some(source_map.clone()),
                                         false,
+                                        false,
                                         false);
         let handler = Handler::with_emitter(true, None, Box::new(emitter));
         handler.span_err(msp, "foo");
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs
index db416e7eb03..759d9ab6a40 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs
@@ -12,14 +12,14 @@ const fn foo() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
-const fn bar() -> u32 { foo() } //~ ERROR can only call other `min_const_fn`
+const fn bar() -> u32 { foo() } //~ ERROR can only call other `const fn`
 
 #[unstable(feature = "rust1", issue="0")]
 const fn foo2() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
-const fn bar2() -> u32 { foo2() } //~ ERROR can only call other `min_const_fn`
+const fn bar2() -> u32 { foo2() } //~ ERROR can only call other `const fn`
 
 #[stable(feature = "rust1", since = "1.0.0")]
 // conformity is required, even with `const_fn` feature gate
@@ -31,6 +31,6 @@ const fn foo2_gated() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
-const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `min_const_fn`
+const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `const fn`
 
 fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr
index a8d0dc37e40..c73eda9ab9f 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr
@@ -1,4 +1,4 @@
-error[E0723]: can only call other `min_const_fn` within a `min_const_fn` (see issue #57563)
+error[E0723]: can only call other `const fn` within a `const fn`, but `const foo` is not stable as `const fn` (see issue #57563)
   --> $DIR/min_const_fn_libstd_stability.rs:15:25
    |
 LL | const fn bar() -> u32 { foo() }
@@ -6,7 +6,7 @@ LL | const fn bar() -> u32 { foo() }
    |
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
-error[E0723]: can only call other `min_const_fn` within a `min_const_fn` (see issue #57563)
+error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2` is not stable as `const fn` (see issue #57563)
   --> $DIR/min_const_fn_libstd_stability.rs:22:26
    |
 LL | const fn bar2() -> u32 { foo2() }
@@ -22,7 +22,7 @@ LL | const fn bar3() -> u32 { (5f32 + 6f32) as u32 }
    |
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
-error[E0723]: can only call other `min_const_fn` within a `min_const_fn` (see issue #57563)
+error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2_gated` is not stable as `const fn` (see issue #57563)
   --> $DIR/min_const_fn_libstd_stability.rs:34:32
    |
 LL | const fn bar2_gated() -> u32 { foo2_gated() }
diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs
index 7faba480a23..64057b012b8 100644
--- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs
@@ -12,14 +12,14 @@ const unsafe fn foo() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
-const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR can only call other `min_const_fn`
+const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR can only call other `const fn`
 
 #[unstable(feature = "rust1", issue="0")]
 const unsafe fn foo2() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
-const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR can only call other `min_const_fn`
+const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR can only call other `const fn`
 
 #[stable(feature = "rust1", since = "1.0.0")]
 // conformity is required, even with `const_fn` feature gate
@@ -31,6 +31,7 @@ const unsafe fn foo2_gated() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
-const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } //~ ERROR can only call other
+const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } }
+//~^ ERROR can only call other `const fn`
 
 fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr
index 5b2bee19acf..87b572dcc46 100644
--- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr
@@ -1,4 +1,4 @@
-error[E0723]: can only call other `min_const_fn` within a `min_const_fn` (see issue #57563)
+error[E0723]: can only call other `const fn` within a `const fn`, but `const foo` is not stable as `const fn` (see issue #57563)
   --> $DIR/min_const_unsafe_fn_libstd_stability.rs:15:41
    |
 LL | const unsafe fn bar() -> u32 { unsafe { foo() } }
@@ -6,7 +6,7 @@ LL | const unsafe fn bar() -> u32 { unsafe { foo() } }
    |
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
-error[E0723]: can only call other `min_const_fn` within a `min_const_fn` (see issue #57563)
+error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2` is not stable as `const fn` (see issue #57563)
   --> $DIR/min_const_unsafe_fn_libstd_stability.rs:22:42
    |
 LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } }
@@ -22,7 +22,7 @@ LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 }
    |
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
-error[E0723]: can only call other `min_const_fn` within a `min_const_fn` (see issue #57563)
+error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2_gated` is not stable as `const fn` (see issue #57563)
   --> $DIR/min_const_unsafe_fn_libstd_stability.rs:34:48
    |
 LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } }
diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs
index bc1d5091f38..deb2cb6b619 100644
--- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs
@@ -12,14 +12,14 @@ const fn foo() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
-const unsafe fn bar() -> u32 { foo() } //~ ERROR can only call other `min_const_fn`
+const unsafe fn bar() -> u32 { foo() } //~ ERROR can only call other `const fn`
 
 #[unstable(feature = "rust1", issue="0")]
 const fn foo2() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
-const unsafe fn bar2() -> u32 { foo2() } //~ ERROR can only call other `min_const_fn`
+const unsafe fn bar2() -> u32 { foo2() } //~ ERROR can only call other `const fn`
 
 // check whether this function cannot be called even with the feature gate active
 #[unstable(feature = "foo2", issue="0")]
@@ -27,6 +27,6 @@ const fn foo2_gated() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
-const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `min_const_fn`
+const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `const fn`
 
 fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr
index f7f630c9ae3..5fddc119758 100644
--- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr
@@ -1,4 +1,4 @@
-error[E0723]: can only call other `min_const_fn` within a `min_const_fn` (see issue #57563)
+error[E0723]: can only call other `const fn` within a `const fn`, but `const foo` is not stable as `const fn` (see issue #57563)
   --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:15:32
    |
 LL | const unsafe fn bar() -> u32 { foo() }
@@ -6,7 +6,7 @@ LL | const unsafe fn bar() -> u32 { foo() }
    |
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
-error[E0723]: can only call other `min_const_fn` within a `min_const_fn` (see issue #57563)
+error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2` is not stable as `const fn` (see issue #57563)
   --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:22:33
    |
 LL | const unsafe fn bar2() -> u32 { foo2() }
@@ -14,7 +14,7 @@ LL | const unsafe fn bar2() -> u32 { foo2() }
    |
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
-error[E0723]: can only call other `min_const_fn` within a `min_const_fn` (see issue #57563)
+error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2_gated` is not stable as `const fn` (see issue #57563)
   --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:30:39
    |
 LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() }
diff --git a/src/test/ui/lint/use_suggestion_json.rs b/src/test/ui/lint/use_suggestion_json.rs
index 3bdbaa55f2d..9679ce4a2ae 100644
--- a/src/test/ui/lint/use_suggestion_json.rs
+++ b/src/test/ui/lint/use_suggestion_json.rs
@@ -1,5 +1,6 @@
 // ignore-cloudabi
-// compile-flags: --error-format pretty-json -Zunstable-options
+// ignore-windows
+// compile-flags: --error-format pretty-json -Zunstable-options --json-rendered=termcolor
 
 // The output for humans should just highlight the whole span without showing
 // the suggested replacement, but we also want to test that suggested
diff --git a/src/test/ui/lint/use_suggestion_json.stderr b/src/test/ui/lint/use_suggestion_json.stderr
index dee7f2f9b16..632666db75b 100644
--- a/src/test/ui/lint/use_suggestion_json.stderr
+++ b/src/test/ui/lint/use_suggestion_json.stderr
@@ -73,10 +73,10 @@ mod foo {
   "spans": [
     {
       "file_name": "$DIR/use_suggestion_json.rs",
-      "byte_start": 440,
-      "byte_end": 444,
-      "line_start": 11,
-      "line_end": 11,
+      "byte_start": 484,
+      "byte_end": 488,
+      "line_start": 12,
+      "line_end": 12,
       "column_start": 12,
       "column_end": 16,
       "is_primary": true,
@@ -101,10 +101,10 @@ mod foo {
       "spans": [
         {
           "file_name": "$DIR/use_suggestion_json.rs",
-          "byte_start": 417,
-          "byte_end": 417,
-          "line_start": 10,
-          "line_end": 10,
+          "byte_start": 461,
+          "byte_end": 461,
+          "line_start": 11,
+          "line_end": 11,
           "column_start": 1,
           "column_end": 1,
           "is_primary": true,
@@ -124,10 +124,10 @@ mod foo {
         },
         {
           "file_name": "$DIR/use_suggestion_json.rs",
-          "byte_start": 417,
-          "byte_end": 417,
-          "line_start": 10,
-          "line_end": 10,
+          "byte_start": 461,
+          "byte_end": 461,
+          "line_start": 11,
+          "line_end": 11,
           "column_start": 1,
           "column_end": 1,
           "is_primary": true,
@@ -147,10 +147,10 @@ mod foo {
         },
         {
           "file_name": "$DIR/use_suggestion_json.rs",
-          "byte_start": 417,
-          "byte_end": 417,
-          "line_start": 10,
-          "line_end": 10,
+          "byte_start": 461,
+          "byte_end": 461,
+          "line_start": 11,
+          "line_end": 11,
           "column_start": 1,
           "column_end": 1,
           "is_primary": true,
@@ -170,10 +170,10 @@ mod foo {
         },
         {
           "file_name": "$DIR/use_suggestion_json.rs",
-          "byte_start": 417,
-          "byte_end": 417,
-          "line_start": 10,
-          "line_end": 10,
+          "byte_start": 461,
+          "byte_end": 461,
+          "line_start": 11,
+          "line_end": 11,
           "column_start": 1,
           "column_end": 1,
           "is_primary": true,
@@ -193,10 +193,10 @@ mod foo {
         },
         {
           "file_name": "$DIR/use_suggestion_json.rs",
-          "byte_start": 417,
-          "byte_end": 417,
-          "line_start": 10,
-          "line_end": 10,
+          "byte_start": 461,
+          "byte_end": 461,
+          "line_start": 11,
+          "line_end": 11,
           "column_start": 1,
           "column_end": 1,
           "is_primary": true,
@@ -216,10 +216,10 @@ mod foo {
         },
         {
           "file_name": "$DIR/use_suggestion_json.rs",
-          "byte_start": 417,
-          "byte_end": 417,
-          "line_start": 10,
-          "line_end": 10,
+          "byte_start": 461,
+          "byte_end": 461,
+          "line_start": 11,
+          "line_end": 11,
           "column_start": 1,
           "column_end": 1,
           "is_primary": true,
@@ -239,10 +239,10 @@ mod foo {
         },
         {
           "file_name": "$DIR/use_suggestion_json.rs",
-          "byte_start": 417,
-          "byte_end": 417,
-          "line_start": 10,
-          "line_end": 10,
+          "byte_start": 461,
+          "byte_end": 461,
+          "line_start": 11,
+          "line_end": 11,
           "column_start": 1,
           "column_end": 1,
           "is_primary": true,
@@ -262,10 +262,10 @@ mod foo {
         },
         {
           "file_name": "$DIR/use_suggestion_json.rs",
-          "byte_start": 417,
-          "byte_end": 417,
-          "line_start": 10,
-          "line_end": 10,
+          "byte_start": 461,
+          "byte_end": 461,
+          "line_start": 11,
+          "line_end": 11,
           "column_start": 1,
           "column_end": 1,
           "is_primary": true,
@@ -285,10 +285,10 @@ mod foo {
         },
         {
           "file_name": "$DIR/use_suggestion_json.rs",
-          "byte_start": 417,
-          "byte_end": 417,
-          "line_start": 10,
-          "line_end": 10,
+          "byte_start": 461,
+          "byte_end": 461,
+          "line_start": 11,
+          "line_end": 11,
           "column_start": 1,
           "column_end": 1,
           "is_primary": true,
@@ -308,10 +308,10 @@ mod foo {
         },
         {
           "file_name": "$DIR/use_suggestion_json.rs",
-          "byte_start": 417,
-          "byte_end": 417,
-          "line_start": 10,
-          "line_end": 10,
+          "byte_start": 461,
+          "byte_end": 461,
+          "line_start": 11,
+          "line_end": 11,
           "column_start": 1,
           "column_end": 1,
           "is_primary": true,
@@ -331,10 +331,10 @@ mod foo {
         },
         {
           "file_name": "$DIR/use_suggestion_json.rs",
-          "byte_start": 417,
-          "byte_end": 417,
-          "line_start": 10,
-          "line_end": 10,
+          "byte_start": 461,
+          "byte_end": 461,
+          "line_start": 11,
+          "line_end": 11,
           "column_start": 1,
           "column_end": 1,
           "is_primary": true,
@@ -354,10 +354,10 @@ mod foo {
         },
         {
           "file_name": "$DIR/use_suggestion_json.rs",
-          "byte_start": 417,
-          "byte_end": 417,
-          "line_start": 10,
-          "line_end": 10,
+          "byte_start": 461,
+          "byte_end": 461,
+          "line_start": 11,
+          "line_end": 11,
           "column_start": 1,
           "column_end": 1,
           "is_primary": true,
@@ -380,22 +380,22 @@ mod foo {
       "rendered": null
     }
   ],
-  "rendered": "error[E0412]: cannot find type `Iter` in this scope
-  --> $DIR/use_suggestion_json.rs:11:12
-   |
-LL |     let x: Iter;
-   |            ^^^^ not found in this scope
-help: possible candidates are found in other modules, you can import them into scope
-   |
-LL | use std::collections::binary_heap::Iter;
-   |
-LL | use std::collections::btree_map::Iter;
-   |
-LL | use std::collections::btree_set::Iter;
-   |
-LL | use std::collections::hash_map::Iter;
-   |
-and 8 other candidates
+  "rendered": "\u001b[0m\u001b[1m\u001b[38;5;9merror[E0412]\u001b[0m\u001b[0m\u001b[1m: cannot find type `Iter` in this scope\u001b[0m
+\u001b[0m  \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0m$DIR/use_suggestion_json.rs:12:12\u001b[0m
+\u001b[0m   \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
+\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0m    let x: Iter;\u001b[0m
+\u001b[0m   \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0m           \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9m^^^^\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9mnot found in this scope\u001b[0m
+\u001b[0m\u001b[1m\u001b[38;5;14mhelp\u001b[0m\u001b[0m: possible candidates are found in other modules, you can import them into scope\u001b[0m
+\u001b[0m   \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
+\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0muse std::collections::binary_heap::Iter;\u001b[0m
+\u001b[0m   \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
+\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0muse std::collections::btree_map::Iter;\u001b[0m
+\u001b[0m   \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
+\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0muse std::collections::btree_set::Iter;\u001b[0m
+\u001b[0m   \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
+\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0muse std::collections::hash_map::Iter;\u001b[0m
+\u001b[0m   \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
+\u001b[0mand 8 other candidates\u001b[0m
 
 "
 }
@@ -405,7 +405,7 @@ and 8 other candidates
   "level": "error",
   "spans": [],
   "children": [],
-  "rendered": "error: aborting due to previous error
+  "rendered": "\u001b[0m\u001b[1m\u001b[38;5;9merror\u001b[0m\u001b[0m\u001b[1m: aborting due to previous error\u001b[0m
 
 "
 }
@@ -415,6 +415,6 @@ and 8 other candidates
   "level": "",
   "spans": [],
   "children": [],
-  "rendered": "For more information about this error, try `rustc --explain E0412`.
+  "rendered": "\u001b[0m\u001b[1mFor more information about this error, try `rustc --explain E0412`.\u001b[0m
 "
 }
diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs
index ba919f4c411..a7615f5f423 100644
--- a/src/tools/compiletest/src/json.rs
+++ b/src/tools/compiletest/src/json.rs
@@ -62,7 +62,7 @@ struct DiagnosticCode {
     explanation: Option<String>,
 }
 
-pub fn extract_rendered(output: &str, proc_res: &ProcRes) -> String {
+pub fn extract_rendered(output: &str) -> String {
     output
         .lines()
         .filter_map(|line| {
@@ -70,11 +70,12 @@ pub fn extract_rendered(output: &str, proc_res: &ProcRes) -> String {
                 match serde_json::from_str::<Diagnostic>(line) {
                     Ok(diagnostic) => diagnostic.rendered,
                     Err(error) => {
-                        proc_res.fatal(Some(&format!(
+                        print!(
                             "failed to decode compiler output as json: \
                              `{}`\nline: {}\noutput: {}",
                             error, line, output
-                        )));
+                        );
+                        panic!()
                     }
                 }
             } else {
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 369bb3fefe5..6df56168973 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -2090,50 +2090,10 @@ impl<'test> TestCx<'test> {
     }
 
     fn fatal_proc_rec(&self, err: &str, proc_res: &ProcRes) -> ! {
-        self.try_print_open_handles();
         self.error(err);
         proc_res.fatal(None);
     }
 
-    // This function is a poor man's attempt to debug rust-lang/rust#38620, if
-    // that's closed then this should be deleted
-    //
-    // This is a very "opportunistic" debugging attempt, so we ignore all
-    // errors here.
-    fn try_print_open_handles(&self) {
-        if !cfg!(windows) {
-            return;
-        }
-        if self.config.mode != Incremental {
-            return;
-        }
-
-        let filename = match self.testpaths.file.file_stem() {
-            Some(path) => path,
-            None => return,
-        };
-
-        let mut cmd = Command::new("handle.exe");
-        cmd.arg("-a").arg("-u");
-        cmd.arg(filename);
-        cmd.arg("-nobanner");
-        cmd.stdout(Stdio::piped());
-        cmd.stderr(Stdio::piped());
-        let output = match cmd.spawn().and_then(read2_abbreviated) {
-            Ok(output) => output,
-            Err(_) => return,
-        };
-        println!("---------------------------------------------------");
-        println!("ran extra command to debug rust-lang/rust#38620: ");
-        println!("{:?}", cmd);
-        println!("result: {}", output.status);
-        println!("--- stdout ----------------------------------------");
-        println!("{}", String::from_utf8_lossy(&output.stdout));
-        println!("--- stderr ----------------------------------------");
-        println!("{}", String::from_utf8_lossy(&output.stderr));
-        println!("---------------------------------------------------");
-    }
-
     // codegen tests (using FileCheck)
 
     fn compile_test_and_save_ir(&self) -> ProcRes {
@@ -2844,7 +2804,7 @@ impl<'test> TestCx<'test> {
         let stderr = if explicit {
             proc_res.stderr.clone()
         } else {
-            json::extract_rendered(&proc_res.stderr, &proc_res)
+            json::extract_rendered(&proc_res.stderr)
         };
 
         let normalized_stderr = self.normalize_output(&stderr, &self.props.normalize_stderr);
@@ -3464,7 +3424,9 @@ impl ProcRes {
              {}\n\
              ------------------------------------------\n\
              \n",
-            self.status, self.cmdline, self.stdout, self.stderr
+            self.status, self.cmdline,
+            json::extract_rendered(&self.stdout),
+            json::extract_rendered(&self.stderr),
         );
         // Use resume_unwind instead of panic!() to prevent a panic message + backtrace from
         // compiletest, which is unnecessary noise.