about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-11-09 23:19:55 +0000
committerbors <bors@rust-lang.org>2022-11-09 23:19:55 +0000
commit34115d040b43d9a0dcc313c6282520a86d1e6f61 (patch)
tree13aa86008ab3c54ca9b4fc639c8ff38cf1a842a7
parente75aab045fc476f176a58c408f6b06f0e275c6e1 (diff)
parent70c04a2fd1738ece290631c53c59616c30febdf9 (diff)
downloadrust-34115d040b43d9a0dcc313c6282520a86d1e6f61.tar.gz
rust-34115d040b43d9a0dcc313c6282520a86d1e6f61.zip
Auto merge of #104215 - Manishearth:rollup-5r957ad, r=Manishearth
Rollup of 9 pull requests

Successful merges:

 - #101005 (Migrate rustc_codegen_llvm to SessionDiagnostics)
 - #103307 (Add context to compiler error message)
 - #103464 (Add support for custom mir)
 - #103929 (Cleanup Apple-related code in rustc_target)
 - #104015 (Remove linuxkernel targets)
 - #104020 (Limit efiapi calling convention to supported arches)
 - #104156 (Cleanups in autoderef impl)
 - #104171 (Update books)
 - #104184 (Fix `rustdoc --version` when used with download-rustc)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs2
-rw-r--r--compiler/rustc_borrowck/src/lib.rs14
-rw-r--r--compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs18
-rw-r--r--compiler/rustc_codegen_llvm/src/back/archive.rs35
-rw-r--r--compiler/rustc_codegen_llvm/src/back/lto.rs9
-rw-r--r--compiler/rustc_codegen_llvm/src/consts.rs16
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/errors.rs139
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs38
-rw-r--r--compiler/rustc_codegen_llvm/src/mono_item.rs7
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs24
-rw-r--r--compiler/rustc_driver/src/lib.rs42
-rw-r--r--compiler/rustc_error_messages/locales/en-US/codegen_llvm.ftl58
-rw-r--r--compiler/rustc_error_messages/src/lib.rs1
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs32
-rw-r--r--compiler/rustc_errors/src/diagnostic_impls.rs6
-rw-r--r--compiler/rustc_feature/src/active.rs2
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/autoderef.rs19
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs7
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs3
-rw-r--r--compiler/rustc_interface/src/lib.rs1
-rw-r--r--compiler/rustc_interface/src/util.rs22
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs59
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs8
-rw-r--r--compiler/rustc_mir_build/src/build/custom/mod.rs155
-rw-r--r--compiler/rustc_mir_build/src/build/custom/parse.rs245
-rw-r--r--compiler/rustc_mir_build/src/build/custom/parse/instruction.rs72
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs17
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs16
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/mod.rs11
-rw-r--r--compiler/rustc_mir_transform/src/check_unsafety.rs8
-rw-r--r--compiler/rustc_mir_transform/src/pass_manager.rs73
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_target/src/spec/aarch64_apple_darwin.rs19
-rw-r--r--compiler/rustc_target/src/spec/aarch64_apple_ios.rs20
-rw-r--r--compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs7
-rw-r--r--compiler/rustc_target/src/spec/aarch64_apple_ios_sim.rs22
-rw-r--r--compiler/rustc_target/src/spec/aarch64_apple_tvos.rs7
-rw-r--r--compiler/rustc_target/src/spec/aarch64_apple_watchos_sim.rs22
-rw-r--r--compiler/rustc_target/src/spec/apple_base.rs125
-rw-r--r--compiler/rustc_target/src/spec/apple_sdk_base.rs81
-rw-r--r--compiler/rustc_target/src/spec/arm64_32_apple_watchos.rs2
-rw-r--r--compiler/rustc_target/src/spec/armv7_apple_ios.rs15
-rw-r--r--compiler/rustc_target/src/spec/armv7k_apple_watchos.rs8
-rw-r--r--compiler/rustc_target/src/spec/armv7s_apple_ios.rs7
-rw-r--r--compiler/rustc_target/src/spec/i386_apple_ios.rs16
-rw-r--r--compiler/rustc_target/src/spec/i686_apple_darwin.rs24
-rw-r--r--compiler/rustc_target/src/spec/linux_kernel_base.rs18
-rw-r--r--compiler/rustc_target/src/spec/mod.rs10
-rw-r--r--compiler/rustc_target/src/spec/tests/tests_impl.rs9
-rw-r--r--compiler/rustc_target/src/spec/x86_64_apple_darwin.rs22
-rw-r--r--compiler/rustc_target/src/spec/x86_64_apple_ios.rs12
-rw-r--r--compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs7
-rw-r--r--compiler/rustc_target/src/spec/x86_64_apple_tvos.rs8
-rw-r--r--compiler/rustc_target/src/spec/x86_64_apple_watchos_sim.rs14
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_none_linuxkernel.rs28
-rw-r--r--compiler/rustc_trait_selection/src/autoderef.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs1
-rw-r--r--library/core/src/intrinsics.rs3
-rw-r--r--library/core/src/intrinsics/mir.rs123
-rw-r--r--library/core/src/pin.rs2
-rw-r--r--library/unwind/src/lib.rs1
m---------src/doc/book0
m---------src/doc/nomicon0
m---------src/doc/reference0
m---------src/doc/rust-by-example0
m---------src/doc/rustc-dev-guide0
-rw-r--r--src/doc/rustc/src/platform-support.md1
-rw-r--r--src/librustdoc/config.rs2
-rw-r--r--src/librustdoc/html/layout.rs2
-rw-r--r--src/test/mir-opt/building/custom/references.immut_ref.built.after.mir14
-rw-r--r--src/test/mir-opt/building/custom/references.mut_ref.built.after.mir14
-rw-r--r--src/test/mir-opt/building/custom/references.rs43
-rw-r--r--src/test/mir-opt/building/custom/simple_assign.rs37
-rw-r--r--src/test/mir-opt/building/custom/simple_assign.simple.built.after.mir18
-rw-r--r--src/test/mir-opt/building/custom/simple_assign.simple_ref.built.after.mir10
-rw-r--r--src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.stderr2
-rw-r--r--src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr2
-rw-r--r--src/test/ui/borrowck/issue-11493.stderr2
-rw-r--r--src/test/ui/borrowck/issue-17545.stderr2
-rw-r--r--src/test/ui/borrowck/issue-36082.fixed2
-rw-r--r--src/test/ui/borrowck/issue-36082.rs2
-rw-r--r--src/test/ui/borrowck/issue-36082.stderr2
-rw-r--r--src/test/ui/cleanup-rvalue-scopes-cf.stderr14
-rw-r--r--src/test/ui/consts/const-eval/const-eval-intrinsic-promotion.stderr2
-rw-r--r--src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr6
-rw-r--r--src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.stderr4
-rw-r--r--src/test/ui/consts/const-eval/promoted_const_fn_fail.stderr2
-rw-r--r--src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.stderr2
-rw-r--r--src/test/ui/consts/const-eval/promoted_raw_ptr_ops.stderr8
-rw-r--r--src/test/ui/consts/const-eval/transmute-const-promotion.stderr2
-rw-r--r--src/test/ui/consts/const-eval/union_promotion.stderr2
-rw-r--r--src/test/ui/consts/const-int-conversion.stderr14
-rw-r--r--src/test/ui/consts/const-int-overflowing.stderr6
-rw-r--r--src/test/ui/consts/const-int-rotate.stderr4
-rw-r--r--src/test/ui/consts/const-int-sign.stderr4
-rw-r--r--src/test/ui/consts/const-int-wrapping.stderr10
-rw-r--r--src/test/ui/consts/const-mut-refs/mut_ref_in_final.stderr10
-rw-r--r--src/test/ui/consts/const-ptr-nonnull.stderr4
-rw-r--r--src/test/ui/consts/const-ptr-unique.stderr2
-rw-r--r--src/test/ui/consts/control-flow/interior-mutability.stderr6
-rw-r--r--src/test/ui/consts/issue-54224.stderr4
-rw-r--r--src/test/ui/consts/min_const_fn/promotion.stderr12
-rw-r--r--src/test/ui/consts/promote-not.stderr40
-rw-r--r--src/test/ui/consts/promote_const_let.stderr2
-rw-r--r--src/test/ui/consts/promoted-const-drop.stderr4
-rw-r--r--src/test/ui/consts/qualif-union.stderr10
-rw-r--r--src/test/ui/feature-gates/feature-gate-abi-efiapi.rs33
-rw-r--r--src/test/ui/feature-gates/feature-gate-abi-efiapi.stderr66
-rw-r--r--src/test/ui/feature-gates/feature-gate-abi.rs8
-rw-r--r--src/test/ui/feature-gates/feature-gate-abi.stderr119
-rw-r--r--src/test/ui/feature-gates/feature-gate-custom_mir.rs12
-rw-r--r--src/test/ui/feature-gates/feature-gate-custom_mir.stderr11
-rw-r--r--src/test/ui/generator/auto-trait-regions.stderr4
-rw-r--r--src/test/ui/generic-associated-types/bugs/hrtb-implied-1.stderr2
-rw-r--r--src/test/ui/issues/issue-47184.stderr2
-rw-r--r--src/test/ui/issues/issue-52049.stderr2
-rw-r--r--src/test/ui/lifetimes/borrowck-let-suggestion.stderr2
-rw-r--r--src/test/ui/nll/borrowed-temporary-error.stderr2
-rw-r--r--src/test/ui/nll/issue-57265-return-type-wf-check.stderr2
-rw-r--r--src/test/ui/nll/user-annotations/patterns.stderr6
-rw-r--r--src/test/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr4
-rw-r--r--src/test/ui/regions/regions-free-region-ordering-caller1.stderr2
-rw-r--r--src/test/ui/regions/regions-var-type-out-of-scope.stderr2
-rw-r--r--src/test/ui/span/borrowck-let-suggestion-suffixes.rs6
-rw-r--r--src/test/ui/span/borrowck-let-suggestion-suffixes.stderr6
-rw-r--r--src/test/ui/span/borrowck-ref-into-rvalue.stderr2
-rw-r--r--src/test/ui/span/issue-15480.stderr2
-rw-r--r--src/test/ui/span/regions-close-over-borrowed-ref-in-obj.stderr2
-rw-r--r--src/test/ui/span/slice-borrow.stderr2
-rw-r--r--src/test/ui/static/static-drop-scope.stderr4
-rw-r--r--src/test/ui/static/static-reference-to-fn-2.stderr6
-rw-r--r--src/test/ui/static/static-region-bound.stderr2
-rw-r--r--src/test/ui/statics/issue-44373.stderr2
-rw-r--r--src/test/ui/target-feature/tied-features-cli.one.stderr2
-rw-r--r--src/test/ui/target-feature/tied-features-cli.three.stderr2
-rw-r--r--src/test/ui/target-feature/tied-features-cli.two.stderr2
143 files changed, 1782 insertions, 695 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 7f26e970e30..86cae5d09b5 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -1557,7 +1557,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         }
 
         let mut err = self.temporary_value_borrowed_for_too_long(proper_span);
-        err.span_label(proper_span, "creates a temporary which is freed while still in use");
+        err.span_label(proper_span, "creates a temporary value which is freed while still in use");
         err.span_label(drop_span, "temporary value is freed at the end of this statement");
 
         match explanation {
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index abfe253d43d..4a4887f1970 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -18,6 +18,7 @@ extern crate tracing;
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::graph::dominators::Dominators;
+use rustc_data_structures::vec_map::VecMap;
 use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
@@ -129,6 +130,19 @@ fn mir_borrowck<'tcx>(
 ) -> &'tcx BorrowCheckResult<'tcx> {
     let (input_body, promoted) = tcx.mir_promoted(def);
     debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id()));
+
+    if input_body.borrow().should_skip() {
+        debug!("Skipping borrowck because of injected body");
+        // Let's make up a borrowck result! Fun times!
+        let result = BorrowCheckResult {
+            concrete_opaque_types: VecMap::new(),
+            closure_requirements: None,
+            used_mut_upvars: SmallVec::new(),
+            tainted_by_errors: None,
+        };
+        return tcx.arena.alloc(result);
+    }
+
     let hir_owner = tcx.hir().local_def_id_to_hir_id(def.did).owner;
 
     let infcx =
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
index c55db2017ee..2ba012a77b0 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
@@ -59,7 +59,7 @@ impl DebugContext {
 
         let producer = format!(
             "cg_clif (rustc {}, cranelift {})",
-            rustc_interface::util::version_str().unwrap_or("unknown version"),
+            rustc_interface::util::rustc_version_str().unwrap_or("unknown version"),
             cranelift_codegen::VERSION,
         );
         let comp_dir = tcx
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index d96da5cc11d..a8b47633519 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -12,6 +12,7 @@ use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtec
 use smallvec::SmallVec;
 
 use crate::attributes;
+use crate::errors::{MissingFeatures, SanitizerMemtagRequiresMte, TargetFeatureDisableOrEnable};
 use crate::llvm::AttributePlace::Function;
 use crate::llvm::{self, AllocKindFlags, Attribute, AttributeKind, AttributePlace, MemoryEffects};
 use crate::llvm_util;
@@ -82,7 +83,7 @@ pub fn sanitize_attrs<'ll>(
         let mte_feature =
             features.iter().map(|s| &s[..]).rfind(|n| ["+mte", "-mte"].contains(&&n[..]));
         if let None | Some("-mte") = mte_feature {
-            cx.tcx.sess.err("`-Zsanitizer=memtag` requires `-Ctarget-feature=+mte`");
+            cx.tcx.sess.emit_err(SanitizerMemtagRequiresMte);
         }
 
         attrs.push(llvm::AttributeKind::SanitizeMemTag.create_attr(cx.llcx));
@@ -393,13 +394,14 @@ pub fn from_fn_attrs<'ll, 'tcx>(
             .get_attrs(instance.def_id(), sym::target_feature)
             .next()
             .map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span);
-        let msg = format!(
-            "the target features {} must all be either enabled or disabled together",
-            f.join(", ")
-        );
-        let mut err = cx.tcx.sess.struct_span_err(span, &msg);
-        err.help("add the missing features in a `target_feature` attribute");
-        err.emit();
+        cx.tcx
+            .sess
+            .create_err(TargetFeatureDisableOrEnable {
+                features: f,
+                span: Some(span),
+                missing_features: Some(MissingFeatures),
+            })
+            .emit();
         return;
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index 082665bba38..5c68abeb08b 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -12,6 +12,10 @@ use std::str;
 use object::read::macho::FatArch;
 
 use crate::common;
+use crate::errors::{
+    ArchiveBuildFailure, DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary,
+    ErrorWritingDEFFile, UnknownArchiveKind,
+};
 use crate::llvm::archive_ro::{ArchiveRO, Child};
 use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
 use rustc_codegen_ssa::back::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
@@ -147,7 +151,7 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
     fn build(mut self: Box<Self>, output: &Path) -> bool {
         match self.build_with_llvm(output) {
             Ok(any_members) => any_members,
-            Err(e) => self.sess.fatal(&format!("failed to build archive: {}", e)),
+            Err(e) => self.sess.emit_fatal(ArchiveBuildFailure { error: e }),
         }
     }
 }
@@ -217,7 +221,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
             match std::fs::write(&def_file_path, def_file_content) {
                 Ok(_) => {}
                 Err(e) => {
-                    sess.fatal(&format!("Error writing .DEF file: {}", e));
+                    sess.emit_fatal(ErrorWritingDEFFile { error: e });
                 }
             };
 
@@ -239,13 +243,14 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
 
             match result {
                 Err(e) => {
-                    sess.fatal(&format!("Error calling dlltool: {}", e));
+                    sess.emit_fatal(ErrorCallingDllTool { error: e });
+                }
+                Ok(output) if !output.status.success() => {
+                    sess.emit_fatal(DlltoolFailImportLibrary {
+                        stdout: String::from_utf8_lossy(&output.stdout),
+                        stderr: String::from_utf8_lossy(&output.stderr),
+                    })
                 }
-                Ok(output) if !output.status.success() => sess.fatal(&format!(
-                    "Dlltool could not create import library: {}\n{}",
-                    String::from_utf8_lossy(&output.stdout),
-                    String::from_utf8_lossy(&output.stderr)
-                )),
                 _ => {}
             }
         } else {
@@ -293,11 +298,10 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
             };
 
             if result == crate::llvm::LLVMRustResult::Failure {
-                sess.fatal(&format!(
-                    "Error creating import library for {}: {}",
+                sess.emit_fatal(ErrorCreatingImportLibrary {
                     lib_name,
-                    llvm::last_error().unwrap_or("unknown LLVM error".to_string())
-                ));
+                    error: llvm::last_error().unwrap_or("unknown LLVM error".to_string()),
+                });
             }
         };
 
@@ -308,9 +312,10 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
 impl<'a> LlvmArchiveBuilder<'a> {
     fn build_with_llvm(&mut self, output: &Path) -> io::Result<bool> {
         let kind = &*self.sess.target.archive_format;
-        let kind = kind.parse::<ArchiveKind>().map_err(|_| kind).unwrap_or_else(|kind| {
-            self.sess.fatal(&format!("Don't know how to build archive of type: {}", kind))
-        });
+        let kind = kind
+            .parse::<ArchiveKind>()
+            .map_err(|_| kind)
+            .unwrap_or_else(|kind| self.sess.emit_fatal(UnknownArchiveKind { kind }));
 
         let mut additions = mem::take(&mut self.additions);
         let mut strings = Vec::new();
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index a49cc7f8d66..3fa21355b7f 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -1,4 +1,5 @@
 use crate::back::write::{self, save_temp_bitcode, DiagnosticHandlers};
+use crate::errors::DynamicLinkingWithLTO;
 use crate::llvm::{self, build_string};
 use crate::{LlvmCodegenBackend, ModuleLlvm};
 use object::read::archive::ArchiveFile;
@@ -90,13 +91,7 @@ fn prepare_lto(
         }
 
         if cgcx.opts.cg.prefer_dynamic && !cgcx.opts.unstable_opts.dylib_lto {
-            diag_handler
-                .struct_err("cannot prefer dynamic linking when performing LTO")
-                .note(
-                    "only 'staticlib', 'bin', and 'cdylib' outputs are \
-                               supported with LTO",
-                )
-                .emit();
+            diag_handler.emit_err(DynamicLinkingWithLTO);
             return Err(FatalError);
         }
 
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index bf5ac4e503e..3b504d3a7df 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -1,6 +1,7 @@
 use crate::base;
 use crate::common::{self, CodegenCx};
 use crate::debuginfo;
+use crate::errors::{InvalidMinimumAlignment, LinkageConstOrMutType, SymbolAlreadyDefined};
 use crate::llvm::{self, True};
 use crate::llvm_util;
 use crate::type_::Type;
@@ -146,7 +147,7 @@ fn set_global_alignment<'ll>(cx: &CodegenCx<'ll, '_>, gv: &'ll Value, mut align:
         match Align::from_bits(min) {
             Ok(min) => align = align.max(min),
             Err(err) => {
-                cx.sess().err(&format!("invalid minimum global alignment: {}", err));
+                cx.sess().emit_err(InvalidMinimumAlignment { err });
             }
         }
     }
@@ -174,10 +175,7 @@ fn check_and_apply_linkage<'ll, 'tcx>(
         let llty2 = if let ty::RawPtr(ref mt) = ty.kind() {
             cx.layout_of(mt.ty).llvm_type(cx)
         } else {
-            cx.sess().span_fatal(
-                cx.tcx.def_span(def_id),
-                "must have type `*const T` or `*mut T` due to `#[linkage]` attribute",
-            )
+            cx.sess().emit_fatal(LinkageConstOrMutType { span: cx.tcx.def_span(def_id) })
         };
         unsafe {
             // Declare a symbol `foo` with the desired linkage.
@@ -193,10 +191,10 @@ fn check_and_apply_linkage<'ll, 'tcx>(
             let mut real_name = "_rust_extern_with_linkage_".to_string();
             real_name.push_str(sym);
             let g2 = cx.define_global(&real_name, llty).unwrap_or_else(|| {
-                cx.sess().span_fatal(
-                    cx.tcx.def_span(def_id),
-                    &format!("symbol `{}` is already defined", &sym),
-                )
+                cx.sess().emit_fatal(SymbolAlreadyDefined {
+                    span: cx.tcx.def_span(def_id),
+                    symbol_name: sym,
+                })
             });
             llvm::LLVMRustSetLinkage(g2, llvm::Linkage::InternalLinkage);
             llvm::LLVMSetInitializer(g2, g1);
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index c22ec128dac..eaa2ccfc835 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -3,6 +3,7 @@ use crate::back::write::to_llvm_code_model;
 use crate::callee::get_fn;
 use crate::coverageinfo;
 use crate::debuginfo;
+use crate::errors::BranchProtectionRequiresAArch64;
 use crate::llvm;
 use crate::llvm_util;
 use crate::type_::Type;
@@ -26,6 +27,7 @@ use rustc_session::config::{BranchProtection, CFGuard, CFProtection};
 use rustc_session::config::{CrateType, DebugInfo, PAuthKey, PacRet};
 use rustc_session::Session;
 use rustc_span::source_map::Span;
+use rustc_span::source_map::Spanned;
 use rustc_target::abi::{
     call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx,
 };
@@ -275,7 +277,7 @@ pub unsafe fn create_module<'ll>(
 
     if let Some(BranchProtection { bti, pac_ret }) = sess.opts.unstable_opts.branch_protection {
         if sess.target.arch != "aarch64" {
-            sess.err("-Zbranch-protection is only supported on aarch64");
+            sess.emit_err(BranchProtectionRequiresAArch64);
         } else {
             llvm::LLVMRustAddModuleFlag(
                 llmod,
@@ -951,7 +953,7 @@ impl<'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'_, 'tcx> {
     #[inline]
     fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
         if let LayoutError::SizeOverflow(_) = err {
-            self.sess().span_fatal(span, &err.to_string())
+            self.sess().emit_fatal(Spanned { span, node: err })
         } else {
             span_bug!(span, "failed to get layout for `{}`: {}", ty, err)
         }
@@ -969,7 +971,7 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'_, 'tcx> {
         fn_abi_request: FnAbiRequest<'tcx>,
     ) -> ! {
         if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
-            self.sess().span_fatal(span, &err.to_string())
+            self.sess().emit_fatal(Spanned { span, node: err })
         } else {
             match fn_abi_request {
                 FnAbiRequest::OfFnPtr { sig, extra_args } => {
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index 433f043209e..8a8d889a298 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -1,5 +1,6 @@
 use crate::common::CodegenCx;
 use crate::coverageinfo;
+use crate::errors::InstrumentCoverageRequiresLLVM12;
 use crate::llvm;
 
 use llvm::coverageinfo::CounterMappingRegion;
@@ -37,7 +38,7 @@ pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {
     // LLVM 12.
     let version = coverageinfo::mapping_version();
     if version < 4 {
-        tcx.sess.fatal("rustc option `-C instrument-coverage` requires LLVM 12 or higher.");
+        tcx.sess.emit_fatal(InstrumentCoverageRequiresLLVM12);
     }
 
     debug!("Generating coverage map for CodegenUnit: `{}`", cx.codegen_unit.name());
diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs
new file mode 100644
index 00000000000..0fafc214f2f
--- /dev/null
+++ b/compiler/rustc_codegen_llvm/src/errors.rs
@@ -0,0 +1,139 @@
+use std::borrow::Cow;
+
+use rustc_errors::fluent;
+use rustc_errors::DiagnosticBuilder;
+use rustc_errors::ErrorGuaranteed;
+use rustc_errors::Handler;
+use rustc_errors::IntoDiagnostic;
+use rustc_macros::{Diagnostic, Subdiagnostic};
+use rustc_span::Span;
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_unknown_ctarget_feature_prefix)]
+#[note]
+pub(crate) struct UnknownCTargetFeaturePrefix<'a> {
+    pub feature: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_unknown_ctarget_feature)]
+#[note]
+pub(crate) struct UnknownCTargetFeature<'a> {
+    pub feature: &'a str,
+    #[subdiagnostic]
+    pub rust_feature: PossibleFeature<'a>,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum PossibleFeature<'a> {
+    #[help(possible_feature)]
+    Some { rust_feature: &'a str },
+    #[help(consider_filing_feature_request)]
+    None,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_error_creating_import_library)]
+pub(crate) struct ErrorCreatingImportLibrary<'a> {
+    pub lib_name: &'a str,
+    pub error: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_instrument_coverage_requires_llvm_12)]
+pub(crate) struct InstrumentCoverageRequiresLLVM12;
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_symbol_already_defined)]
+pub(crate) struct SymbolAlreadyDefined<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub symbol_name: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_branch_protection_requires_aarch64)]
+pub(crate) struct BranchProtectionRequiresAArch64;
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_invalid_minimum_alignment)]
+pub(crate) struct InvalidMinimumAlignment {
+    pub err: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_linkage_const_or_mut_type)]
+pub(crate) struct LinkageConstOrMutType {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_sanitizer_memtag_requires_mte)]
+pub(crate) struct SanitizerMemtagRequiresMte;
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_archive_build_failure)]
+pub(crate) struct ArchiveBuildFailure {
+    pub error: std::io::Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_error_writing_def_file)]
+pub(crate) struct ErrorWritingDEFFile {
+    pub error: std::io::Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_error_calling_dlltool)]
+pub(crate) struct ErrorCallingDllTool {
+    pub error: std::io::Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_dlltool_fail_import_library)]
+pub(crate) struct DlltoolFailImportLibrary<'a> {
+    pub stdout: Cow<'a, str>,
+    pub stderr: Cow<'a, str>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_unknown_archive_kind)]
+pub(crate) struct UnknownArchiveKind<'a> {
+    pub kind: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_dynamic_linking_with_lto)]
+#[note]
+pub(crate) struct DynamicLinkingWithLTO;
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_fail_parsing_target_machine_config_to_target_machine)]
+pub(crate) struct FailParsingTargetMachineConfigToTargetMachine {
+    pub error: String,
+}
+
+pub(crate) struct TargetFeatureDisableOrEnable<'a> {
+    pub features: &'a [&'a str],
+    pub span: Option<Span>,
+    pub missing_features: Option<MissingFeatures>,
+}
+
+#[derive(Subdiagnostic)]
+#[help(codegen_llvm_missing_features)]
+pub(crate) struct MissingFeatures;
+
+impl IntoDiagnostic<'_, ErrorGuaranteed> for TargetFeatureDisableOrEnable<'_> {
+    fn into_diagnostic(self, sess: &'_ Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
+        let mut diag = sess.struct_err(fluent::codegen_llvm_target_feature_disable_or_enable);
+        if let Some(span) = self.span {
+            diag.set_span(span);
+        };
+        if let Some(missing_features) = self.missing_features {
+            diag.subdiagnostic(missing_features);
+        }
+        diag.set_arg("features", self.features.join(", "));
+        diag
+    }
+}
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index d51aced85df..246e82545c8 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -12,6 +12,8 @@
 #![feature(iter_intersperse)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 
 #[macro_use]
 extern crate rustc_macros;
@@ -20,6 +22,7 @@ extern crate tracing;
 
 use back::write::{create_informational_target_machine, create_target_machine};
 
+use errors::FailParsingTargetMachineConfigToTargetMachine;
 pub use llvm_util::target_features;
 use rustc_ast::expand::allocator::AllocatorKind;
 use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
@@ -62,6 +65,7 @@ mod context;
 mod coverageinfo;
 mod debuginfo;
 mod declare;
+mod errors;
 mod intrinsic;
 
 // The following is a work around that replaces `pub mod llvm;` and that fixes issue 53912.
@@ -412,7 +416,7 @@ impl ModuleLlvm {
             let tm = match (cgcx.tm_factory)(tm_factory_config) {
                 Ok(m) => m,
                 Err(e) => {
-                    handler.struct_err(&e).emit();
+                    handler.emit_err(FailParsingTargetMachineConfigToTargetMachine { error: e });
                     return Err(FatalError);
                 }
             };
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 2fd58567c48..e1f54356228 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -1,4 +1,8 @@
 use crate::back::write::create_informational_target_machine;
+use crate::errors::{
+    PossibleFeature, TargetFeatureDisableOrEnable, UnknownCTargetFeature,
+    UnknownCTargetFeaturePrefix,
+};
 use crate::llvm;
 use libc::c_int;
 use rustc_codegen_ssa::target_features::{
@@ -434,12 +438,7 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
                 Some(c @ '+' | c @ '-') => c,
                 Some(_) => {
                     if diagnostics {
-                        let mut diag = sess.struct_warn(&format!(
-                            "unknown feature specified for `-Ctarget-feature`: `{}`",
-                            s
-                        ));
-                        diag.note("features must begin with a `+` to enable or `-` to disable it");
-                        diag.emit();
+                        sess.emit_warning(UnknownCTargetFeaturePrefix { feature: s });
                     }
                     return None;
                 }
@@ -456,17 +455,15 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
                         None
                     }
                 });
-                let mut diag = sess.struct_warn(&format!(
-                    "unknown feature specified for `-Ctarget-feature`: `{}`",
-                    feature
-                ));
-                diag.note("it is still passed through to the codegen backend");
-                if let Some(rust_feature) = rust_feature {
-                    diag.help(&format!("you might have meant: `{}`", rust_feature));
+                let unknown_feature = if let Some(rust_feature) = rust_feature {
+                    UnknownCTargetFeature {
+                        feature,
+                        rust_feature: PossibleFeature::Some { rust_feature },
+                    }
                 } else {
-                    diag.note("consider filing a feature request");
-                }
-                diag.emit();
+                    UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
+                };
+                sess.emit_warning(unknown_feature);
             }
 
             if diagnostics {
@@ -492,10 +489,11 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
     features.extend(feats);
 
     if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
-        sess.err(&format!(
-            "target features {} must all be enabled or disabled together",
-            f.join(", ")
-        ));
+        sess.emit_err(TargetFeatureDisableOrEnable {
+            features: f,
+            span: None,
+            missing_features: None,
+        });
     }
 
     features
diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs
index 1eceb7f5c87..76f692b2016 100644
--- a/compiler/rustc_codegen_llvm/src/mono_item.rs
+++ b/compiler/rustc_codegen_llvm/src/mono_item.rs
@@ -1,6 +1,7 @@
 use crate::attributes;
 use crate::base;
 use crate::context::CodegenCx;
+use crate::errors::SymbolAlreadyDefined;
 use crate::llvm;
 use crate::type_of::LayoutLlvmExt;
 use rustc_codegen_ssa::traits::*;
@@ -25,10 +26,8 @@ impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'_, 'tcx> {
         let llty = self.layout_of(ty).llvm_type(self);
 
         let g = self.define_global(symbol_name, llty).unwrap_or_else(|| {
-            self.sess().span_fatal(
-                self.tcx.def_span(def_id),
-                &format!("symbol `{}` is already defined", symbol_name),
-            )
+            self.sess()
+                .emit_fatal(SymbolAlreadyDefined { span: self.tcx.def_span(def_id), symbol_name })
         });
 
         unsafe {
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index d0ac016b02e..e3d28a1aca2 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -15,10 +15,8 @@ use rustc_data_structures::profiling::TimingGuard;
 use rustc_data_structures::profiling::VerboseTimingGuard;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::emitter::Emitter;
-use rustc_errors::{
-    translation::{to_fluent_args, Translate},
-    DiagnosticId, FatalError, Handler, Level,
-};
+use rustc_errors::{translation::Translate, DiagnosticId, FatalError, Handler, Level};
+use rustc_errors::{DiagnosticMessage, Style};
 use rustc_fs_util::link_or_copy;
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc_incremental::{
@@ -38,6 +36,7 @@ use rustc_span::{BytePos, FileName, InnerSpan, Pos, Span};
 use rustc_target::spec::{MergeFunctions, SanitizerSet};
 
 use std::any::Any;
+use std::borrow::Cow;
 use std::fs;
 use std::io;
 use std::marker::PhantomData;
@@ -969,8 +968,11 @@ pub enum Message<B: WriteBackendMethods> {
     CodegenAborted,
 }
 
+type DiagnosticArgName<'source> = Cow<'source, str>;
+
 struct Diagnostic {
-    msg: String,
+    msg: Vec<(DiagnosticMessage, Style)>,
+    args: FxHashMap<DiagnosticArgName<'static>, rustc_errors::DiagnosticArgValue<'static>>,
     code: Option<DiagnosticId>,
     lvl: Level,
 }
@@ -1743,15 +1745,18 @@ impl Translate for SharedEmitter {
 
 impl Emitter for SharedEmitter {
     fn emit_diagnostic(&mut self, diag: &rustc_errors::Diagnostic) {
-        let fluent_args = to_fluent_args(diag.args());
+        let args: FxHashMap<Cow<'_, str>, rustc_errors::DiagnosticArgValue<'_>> =
+            diag.args().map(|(name, arg)| (name.clone(), arg.clone())).collect();
         drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic {
-            msg: self.translate_messages(&diag.message, &fluent_args).to_string(),
+            msg: diag.message.clone(),
+            args: args.clone(),
             code: diag.code.clone(),
             lvl: diag.level(),
         })));
         for child in &diag.children {
             drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic {
-                msg: self.translate_messages(&child.message, &fluent_args).to_string(),
+                msg: child.message.clone(),
+                args: args.clone(),
                 code: None,
                 lvl: child.level,
             })));
@@ -1782,10 +1787,11 @@ impl SharedEmitterMain {
             match message {
                 Ok(SharedEmitterMessage::Diagnostic(diag)) => {
                     let handler = sess.diagnostic();
-                    let mut d = rustc_errors::Diagnostic::new(diag.lvl, &diag.msg);
+                    let mut d = rustc_errors::Diagnostic::new_with_messages(diag.lvl, diag.msg);
                     if let Some(code) = diag.code {
                         d.code(code);
                     }
+                    d.replace_args(diag.args);
                     handler.emit_diagnostic(&mut d);
                 }
                 Ok(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source)) => {
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 423f0cdddfd..e043368fdfe 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -6,6 +6,7 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(once_cell)]
+#![feature(decl_macro)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
 #![deny(rustc::untranslatable_diagnostic)]
@@ -753,20 +754,41 @@ fn print_crate_info(
 }
 
 /// Prints version information
-pub fn version(binary: &str, matches: &getopts::Matches) {
+///
+/// NOTE: this is a macro to support drivers built at a different time than the main `rustc_driver` crate.
+pub macro version($binary: literal, $matches: expr) {
+    fn unw(x: Option<&str>) -> &str {
+        x.unwrap_or("unknown")
+    }
+    $crate::version_at_macro_invocation(
+        $binary,
+        $matches,
+        unw(option_env!("CFG_VERSION")),
+        unw(option_env!("CFG_VER_HASH")),
+        unw(option_env!("CFG_VER_DATE")),
+        unw(option_env!("CFG_RELEASE")),
+    )
+}
+
+#[doc(hidden)] // use the macro instead
+pub fn version_at_macro_invocation(
+    binary: &str,
+    matches: &getopts::Matches,
+    version: &str,
+    commit_hash: &str,
+    commit_date: &str,
+    release: &str,
+) {
     let verbose = matches.opt_present("verbose");
 
-    println!("{} {}", binary, util::version_str().unwrap_or("unknown version"));
+    println!("{} {}", binary, version);
 
     if verbose {
-        fn unw(x: Option<&str>) -> &str {
-            x.unwrap_or("unknown")
-        }
         println!("binary: {}", binary);
-        println!("commit-hash: {}", unw(util::commit_hash_str()));
-        println!("commit-date: {}", unw(util::commit_date_str()));
+        println!("commit-hash: {}", commit_hash);
+        println!("commit-date: {}", commit_date);
         println!("host: {}", config::host_triple());
-        println!("release: {}", unw(util::release_str()));
+        println!("release: {}", release);
 
         let debug_flags = matches.opt_strs("Z");
         let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
@@ -1082,7 +1104,7 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
     }
 
     if matches.opt_present("version") {
-        version("rustc", &matches);
+        version!("rustc", &matches);
         return None;
     }
 
@@ -1227,7 +1249,7 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
         format!("we would appreciate a bug report: {}", bug_report_url).into(),
         format!(
             "rustc {} running on {}",
-            util::version_str().unwrap_or("unknown_version"),
+            util::version_str!().unwrap_or("unknown_version"),
             config::host_triple()
         )
         .into(),
diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_llvm.ftl b/compiler/rustc_error_messages/locales/en-US/codegen_llvm.ftl
new file mode 100644
index 00000000000..68a205df6c7
--- /dev/null
+++ b/compiler/rustc_error_messages/locales/en-US/codegen_llvm.ftl
@@ -0,0 +1,58 @@
+codegen_llvm_unknown_ctarget_feature =
+    unknown feature specified for `-Ctarget-feature`: `{$feature}`
+    .note = it is still passed through to the codegen backend
+    .possible_feature = you might have meant: `{$rust_feature}`
+    .consider_filing_feature_request = consider filing a feature request
+
+codegen_llvm_unknown_ctarget_feature_prefix =
+    unknown feature specified for `-Ctarget-feature`: `{$feature}`
+    .note = features must begin with a `+` to enable or `-` to disable it
+
+codegen_llvm_error_creating_import_library =
+    Error creating import library for {$lib_name}: {$error}
+
+codegen_llvm_instrument_coverage_requires_llvm_12 =
+    rustc option `-C instrument-coverage` requires LLVM 12 or higher.
+
+codegen_llvm_symbol_already_defined =
+    symbol `{$symbol_name}` is already defined
+
+codegen_llvm_branch_protection_requires_aarch64 =
+    -Zbranch-protection is only supported on aarch64
+
+codegen_llvm_invalid_minimum_alignment =
+    invalid minimum global alignment: {$err}
+
+codegen_llvm_linkage_const_or_mut_type =
+    must have type `*const T` or `*mut T` due to `#[linkage]` attribute
+
+codegen_llvm_sanitizer_memtag_requires_mte =
+    `-Zsanitizer=memtag` requires `-Ctarget-feature=+mte`
+
+codegen_llvm_archive_build_failure =
+    failed to build archive: {$error}
+
+codegen_llvm_error_writing_def_file =
+    Error writing .DEF file: {$error}
+
+codegen_llvm_error_calling_dlltool =
+    Error calling dlltool: {$error}
+
+codegen_llvm_dlltool_fail_import_library =
+    Dlltool could not create import library: {$stdout}\n{$stderr}
+
+codegen_llvm_unknown_archive_kind =
+    Don't know how to build archive of type: {$kind}
+
+codegen_llvm_target_feature_disable_or_enable =
+    the target features {$features} must all be either enabled or disabled together
+
+codegen_llvm_missing_features =
+    add the missing features in a `target_feature` attribute
+
+codegen_llvm_dynamic_linking_with_lto =
+    cannot prefer dynamic linking when performing LTO
+    .note = only 'staticlib', 'bin', and 'cdylib' outputs are supported with LTO
+
+codegen_llvm_fail_parsing_target_machine_config_to_target_machine =
+    failed to parse target machine config to target machine: {$error}
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 9465051dd10..e34acba1057 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -42,6 +42,7 @@ fluent_messages! {
     borrowck => "../locales/en-US/borrowck.ftl",
     builtin_macros => "../locales/en-US/builtin_macros.ftl",
     codegen_gcc => "../locales/en-US/codegen_gcc.ftl",
+    codegen_llvm => "../locales/en-US/codegen_llvm.ftl",
     codegen_ssa => "../locales/en-US/codegen_ssa.ftl",
     compiletest => "../locales/en-US/compiletest.ftl",
     const_eval => "../locales/en-US/const_eval.ftl",
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index 45c017df918..43101bbb9d3 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -44,6 +44,15 @@ pub trait IntoDiagnosticArg {
     fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static>;
 }
 
+impl<'source> IntoDiagnosticArg for DiagnosticArgValue<'source> {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        match self {
+            DiagnosticArgValue::Str(s) => DiagnosticArgValue::Str(Cow::Owned(s.into_owned())),
+            DiagnosticArgValue::Number(n) => DiagnosticArgValue::Number(n),
+        }
+    }
+}
+
 impl<'source> Into<FluentValue<'source>> for DiagnosticArgValue<'source> {
     fn into(self) -> FluentValue<'source> {
         match self {
@@ -205,6 +214,22 @@ impl Diagnostic {
     }
 
     #[track_caller]
+    pub fn new_with_messages(level: Level, messages: Vec<(DiagnosticMessage, Style)>) -> Self {
+        Diagnostic {
+            level,
+            message: messages,
+            code: None,
+            span: MultiSpan::new(),
+            children: vec![],
+            suggestions: Ok(vec![]),
+            args: Default::default(),
+            sort_span: DUMMY_SP,
+            is_lint: false,
+            emitted_at: DiagnosticLocation::caller(),
+        }
+    }
+
+    #[track_caller]
     pub fn new_with_code<M: Into<DiagnosticMessage>>(
         level: Level,
         code: Option<DiagnosticId>,
@@ -931,6 +956,13 @@ impl Diagnostic {
         self
     }
 
+    pub fn replace_args(
+        &mut self,
+        args: FxHashMap<DiagnosticArgName<'static>, DiagnosticArgValue<'static>>,
+    ) {
+        self.args = args;
+    }
+
     pub fn styled_message(&self) -> &[(DiagnosticMessage, Style)] {
         &self.message
     }
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
index 22f6fc700fa..c6035705e39 100644
--- a/compiler/rustc_errors/src/diagnostic_impls.rs
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -107,6 +107,12 @@ impl IntoDiagnosticArg for String {
     }
 }
 
+impl<'a> IntoDiagnosticArg for Cow<'a, str> {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Owned(self.into_owned()))
+    }
+}
+
 impl<'a> IntoDiagnosticArg for &'a Path {
     fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
         DiagnosticArgValue::Str(Cow::Owned(self.display().to_string()))
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 09a747662e2..e94e038f928 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -152,6 +152,8 @@ declare_features! (
     (active, anonymous_lifetime_in_impl_trait, "1.63.0", None, None),
     /// Allows identifying the `compiler_builtins` crate.
     (active, compiler_builtins, "1.13.0", None, None),
+    /// Allows writing custom MIR
+    (active, custom_mir, "1.65.0", None, None),
     /// Outputs useful `assert!` messages
     (active, generic_assert, "1.63.0", None, None),
     /// Allows using the `rust-intrinsic`'s "ABI".
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 4ff3b3f2a38..dc3a7495684 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -810,6 +810,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     rustc_attr!(TEST, rustc_polymorphize_error, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_def_path, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_mir, Normal, template!(List: "arg1, arg2, ..."), DuplicatesOk),
+    gated!(
+        custom_mir, Normal, template!(List: r#"dialect = "...", phase = "...""#),
+        ErrorFollowing, "the `#[custom_mir]` attribute is just used for the Rust test suite",
+    ),
     rustc_attr!(TEST, rustc_dump_program_clauses, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_dump_env_program_clauses, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_object_lifetime_default, Normal, template!(Word), WarnFollowing),
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 6a12db9d36a..8a70f41c8a8 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1708,8 +1708,7 @@ fn receiver_is_valid<'tcx>(
         return true;
     }
 
-    let mut autoderef =
-        Autoderef::new(infcx, wfcx.param_env, wfcx.body_id, span, receiver_ty, span);
+    let mut autoderef = Autoderef::new(infcx, wfcx.param_env, wfcx.body_id, span, receiver_ty);
 
     // The `arbitrary_self_types` feature allows raw pointer receivers like `self: *const Self`.
     if arbitrary_self_types_enabled {
diff --git a/compiler/rustc_hir_typeck/src/autoderef.rs b/compiler/rustc_hir_typeck/src/autoderef.rs
index 59c366ad7d7..41b52a4c4a9 100644
--- a/compiler/rustc_hir_typeck/src/autoderef.rs
+++ b/compiler/rustc_hir_typeck/src/autoderef.rs
@@ -12,18 +12,7 @@ use std::iter;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> {
-        Autoderef::new(self, self.param_env, self.body_id, span, base_ty, span)
-    }
-
-    /// Like `autoderef`, but provides a custom `Span` to use for calls to
-    /// an overloaded `Deref` operator
-    pub fn autoderef_overloaded_span(
-        &'a self,
-        span: Span,
-        base_ty: Ty<'tcx>,
-        overloaded_span: Span,
-    ) -> Autoderef<'a, 'tcx> {
-        Autoderef::new(self, self.param_env, self.body_id, span, base_ty, overloaded_span)
+        Autoderef::new(self, self.param_env, self.body_id, span, base_ty)
     }
 
     pub fn try_overloaded_deref(
@@ -55,11 +44,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         |InferOk { value: method, obligations: o }| {
                             obligations.extend(o);
                             if let ty::Ref(region, _, mutbl) = *method.sig.output().kind() {
-                                Some(OverloadedDeref {
-                                    region,
-                                    mutbl,
-                                    span: autoderef.overloaded_span(),
-                                })
+                                Some(OverloadedDeref { region, mutbl, span: autoderef.span() })
                             } else {
                                 None
                             }
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index be4ea998622..d996d6ec610 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -151,8 +151,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
     ) -> Ty<'tcx> {
         // Commit the autoderefs by calling `autoderef` again, but this
         // time writing the results into the various typeck results.
-        let mut autoderef =
-            self.autoderef_overloaded_span(self.span, unadjusted_self_ty, self.call_expr.span);
+        let mut autoderef = self.autoderef(self.call_expr.span, unadjusted_self_ty);
         let Some((ty, n)) = autoderef.nth(pick.autoderefs) else {
             return self.tcx.ty_error_with_message(
                 rustc_span::DUMMY_SP,
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index e88701685bc..3fcd073f597 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -475,10 +475,9 @@ fn method_autoderef_steps<'tcx>(
     let (ref infcx, goal, inference_vars) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &goal);
     let ParamEnvAnd { param_env, value: self_ty } = goal;
 
-    let mut autoderef =
-        Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty, DUMMY_SP)
-            .include_raw_pointers()
-            .silence_errors();
+    let mut autoderef = Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty)
+        .include_raw_pointers()
+        .silence_errors();
     let mut reached_raw_pointer = false;
     let mut steps: Vec<_> = autoderef
         .by_ref()
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index c248deb892b..eb10f3e2c10 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -19,7 +19,6 @@ use rustc_span::lev_distance::find_best_match_for_name;
 use rustc_span::source_map::{Span, Spanned};
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{BytePos, DUMMY_SP};
-use rustc_trait_selection::autoderef::Autoderef;
 use rustc_trait_selection::traits::{ObligationCause, Pattern};
 use ty::VariantDef;
 
@@ -2132,7 +2131,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             && let ty::Array(..) | ty::Slice(..) = ty.kind()
         {
             err.help("the semantics of slice patterns changed recently; see issue #62254");
-        } else if Autoderef::new(&self.infcx, self.param_env, self.body_id, span, expected_ty, span)
+        } else if self.autoderef(span, expected_ty)
             .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
             && let (Some(span), true) = (ti.span, ti.origin_expr)
             && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs
index a41a749ee68..542b638bbd7 100644
--- a/compiler/rustc_interface/src/lib.rs
+++ b/compiler/rustc_interface/src/lib.rs
@@ -1,4 +1,5 @@
 #![feature(box_patterns)]
+#![feature(decl_macro)]
 #![feature(internal_output_capture)]
 #![feature(thread_spawn_unchecked)]
 #![feature(once_cell)]
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 62ee72f9883..2fe3fb2fa56 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -327,7 +327,7 @@ fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> M
     let mut file: Option<PathBuf> = None;
 
     let expected_names = &[
-        format!("rustc_codegen_{}-{}", backend_name, release_str().expect("CFG_RELEASE")),
+        format!("rustc_codegen_{}-{}", backend_name, env!("CFG_RELEASE")),
         format!("rustc_codegen_{}", backend_name),
     ];
     for entry in d.filter_map(|e| e.ok()) {
@@ -554,22 +554,12 @@ pub fn build_output_filenames(
     }
 }
 
-/// Returns a version string such as "1.46.0 (04488afe3 2020-08-24)"
-pub fn version_str() -> Option<&'static str> {
+/// Returns a version string such as "1.46.0 (04488afe3 2020-08-24)" when invoked by an in-tree tool.
+pub macro version_str() {
     option_env!("CFG_VERSION")
 }
 
-/// Returns a version string such as "0.12.0-dev".
-pub fn release_str() -> Option<&'static str> {
-    option_env!("CFG_RELEASE")
-}
-
-/// Returns the full SHA1 hash of HEAD of the Git repo from which rustc was built.
-pub fn commit_hash_str() -> Option<&'static str> {
-    option_env!("CFG_VER_HASH")
-}
-
-/// Returns the "commit date" of HEAD of the Git repo from which rustc was built as a static string.
-pub fn commit_date_str() -> Option<&'static str> {
-    option_env!("CFG_VER_DATE")
+/// Returns the version string for `rustc` itself (which may be different from a tool version).
+pub fn rustc_version_str() -> Option<&'static str> {
+    version_str!()
 }
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 0a96d23e354..5290d5aae46 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -138,6 +138,48 @@ impl MirPhase {
             }
         }
     }
+
+    /// Parses an `MirPhase` from a pair of strings. Panics if this isn't possible for any reason.
+    pub fn parse(dialect: String, phase: Option<String>) -> Self {
+        match &*dialect.to_ascii_lowercase() {
+            "built" => {
+                assert!(phase.is_none(), "Cannot specify a phase for `Built` MIR");
+                MirPhase::Built
+            }
+            "analysis" => Self::Analysis(AnalysisPhase::parse(phase)),
+            "runtime" => Self::Runtime(RuntimePhase::parse(phase)),
+            _ => panic!("Unknown MIR dialect {}", dialect),
+        }
+    }
+}
+
+impl AnalysisPhase {
+    pub fn parse(phase: Option<String>) -> Self {
+        let Some(phase) = phase else {
+            return Self::Initial;
+        };
+
+        match &*phase.to_ascii_lowercase() {
+            "initial" => Self::Initial,
+            "post_cleanup" | "post-cleanup" | "postcleanup" => Self::PostCleanup,
+            _ => panic!("Unknown analysis phase {}", phase),
+        }
+    }
+}
+
+impl RuntimePhase {
+    pub fn parse(phase: Option<String>) -> Self {
+        let Some(phase) = phase else {
+            return Self::Initial;
+        };
+
+        match &*phase.to_ascii_lowercase() {
+            "initial" => Self::Initial,
+            "post_cleanup" | "post-cleanup" | "postcleanup" => Self::PostCleanup,
+            "optimized" => Self::Optimized,
+            _ => panic!("Unknown runtime phase {}", phase),
+        }
+    }
 }
 
 impl Display for MirPhase {
@@ -293,6 +335,13 @@ pub struct Body<'tcx> {
     /// potentially allow things like `[u8; std::mem::size_of::<T>() * 0]` due to this.
     pub is_polymorphic: bool,
 
+    /// The phase at which this MIR should be "injected" into the compilation process.
+    ///
+    /// Everything that comes before this `MirPhase` should be skipped.
+    ///
+    /// This is only `Some` if the function that this body comes from was annotated with `rustc_custom_mir`.
+    pub injection_phase: Option<MirPhase>,
+
     pub tainted_by_errors: Option<ErrorGuaranteed>,
 }
 
@@ -339,6 +388,7 @@ impl<'tcx> Body<'tcx> {
             span,
             required_consts: Vec::new(),
             is_polymorphic: false,
+            injection_phase: None,
             tainted_by_errors,
         };
         body.is_polymorphic = body.has_non_region_param();
@@ -366,6 +416,7 @@ impl<'tcx> Body<'tcx> {
             required_consts: Vec::new(),
             var_debug_info: Vec::new(),
             is_polymorphic: false,
+            injection_phase: None,
             tainted_by_errors: None,
         };
         body.is_polymorphic = body.has_non_region_param();
@@ -508,6 +559,14 @@ impl<'tcx> Body<'tcx> {
     pub fn generator_kind(&self) -> Option<GeneratorKind> {
         self.generator.as_ref().map(|generator| generator.generator_kind)
     }
+
+    #[inline]
+    pub fn should_skip(&self) -> bool {
+        let Some(injection_phase) = self.injection_phase else {
+            return false;
+        };
+        injection_phase > self.phase
+    }
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug, TyEncodable, TyDecodable, HashStable)]
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 3312f44c67b..c74d6bc3774 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -189,8 +189,8 @@ pub enum LayoutError<'tcx> {
     NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>),
 }
 
-impl<'a> IntoDiagnostic<'a, !> for LayoutError<'a> {
-    fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, !> {
+impl IntoDiagnostic<'_, !> for LayoutError<'_> {
+    fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, !> {
         let mut diag = handler.struct_fatal("");
 
         match self {
@@ -1126,8 +1126,8 @@ impl<'tcx> fmt::Display for FnAbiError<'tcx> {
     }
 }
 
-impl<'tcx> IntoDiagnostic<'tcx, !> for FnAbiError<'tcx> {
-    fn into_diagnostic(self, handler: &'tcx Handler) -> DiagnosticBuilder<'tcx, !> {
+impl IntoDiagnostic<'_, !> for FnAbiError<'_> {
+    fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, !> {
         handler.struct_fatal(self.to_string())
     }
 }
diff --git a/compiler/rustc_mir_build/src/build/custom/mod.rs b/compiler/rustc_mir_build/src/build/custom/mod.rs
new file mode 100644
index 00000000000..68d8766c907
--- /dev/null
+++ b/compiler/rustc_mir_build/src/build/custom/mod.rs
@@ -0,0 +1,155 @@
+//! Provides the implementation of the `custom_mir` attribute.
+//!
+//! Up until MIR building, this attribute has absolutely no effect. The `mir!` macro is a normal
+//! decl macro that expands like any other, and the code goes through parsing, name resolution and
+//! type checking like all other code. In MIR building we finally detect whether this attribute is
+//! present, and if so we branch off into this module, which implements the attribute by
+//! implementing a custom lowering from THIR to MIR.
+//!
+//! The result of this lowering is returned "normally" from the `mir_built` query, with the only
+//! notable difference being that the `injected` field in the body is set. Various components of the
+//! MIR pipeline, like borrowck and the pass manager will then consult this field (via
+//! `body.should_skip()`) to skip the parts of the MIR pipeline that precede the MIR phase the user
+//! specified.
+//!
+//! This file defines the general framework for the custom parsing. The parsing for all the
+//! "top-level" constructs can be found in the `parse` submodule, while the parsing for statements,
+//! terminators, and everything below can be found in the `parse::instruction` submodule.
+//!
+
+use rustc_ast::Attribute;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::def_id::DefId;
+use rustc_index::vec::IndexVec;
+use rustc_middle::{
+    mir::*,
+    thir::*,
+    ty::{Ty, TyCtxt},
+};
+use rustc_span::Span;
+
+mod parse;
+
+pub(super) fn build_custom_mir<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    did: DefId,
+    thir: &Thir<'tcx>,
+    expr: ExprId,
+    params: &IndexVec<ParamId, Param<'tcx>>,
+    return_ty: Ty<'tcx>,
+    return_ty_span: Span,
+    span: Span,
+    attr: &Attribute,
+) -> Body<'tcx> {
+    let mut body = Body {
+        basic_blocks: BasicBlocks::new(IndexVec::new()),
+        source: MirSource::item(did),
+        phase: MirPhase::Built,
+        source_scopes: IndexVec::new(),
+        generator: None,
+        local_decls: LocalDecls::new(),
+        user_type_annotations: IndexVec::new(),
+        arg_count: params.len(),
+        spread_arg: None,
+        var_debug_info: Vec::new(),
+        span,
+        required_consts: Vec::new(),
+        is_polymorphic: false,
+        tainted_by_errors: None,
+        injection_phase: None,
+        pass_count: 1,
+    };
+
+    body.local_decls.push(LocalDecl::new(return_ty, return_ty_span));
+    body.basic_blocks_mut().push(BasicBlockData::new(None));
+    body.source_scopes.push(SourceScopeData {
+        span,
+        parent_scope: None,
+        inlined: None,
+        inlined_parent_scope: None,
+        local_data: ClearCrossCrate::Clear,
+    });
+    body.injection_phase = Some(parse_attribute(attr));
+
+    let mut pctxt = ParseCtxt {
+        tcx,
+        thir,
+        source_info: SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE },
+        body: &mut body,
+        local_map: FxHashMap::default(),
+        block_map: FxHashMap::default(),
+    };
+
+    let res = (|| {
+        pctxt.parse_args(&params)?;
+        pctxt.parse_body(expr)
+    })();
+    if let Err(err) = res {
+        tcx.sess.diagnostic().span_fatal(
+            err.span,
+            format!("Could not parse {}, found: {:?}", err.expected, err.item_description),
+        )
+    }
+
+    body
+}
+
+fn parse_attribute(attr: &Attribute) -> MirPhase {
+    let meta_items = attr.meta_item_list().unwrap();
+    let mut dialect: Option<String> = None;
+    let mut phase: Option<String> = None;
+
+    for nested in meta_items {
+        let name = nested.name_or_empty();
+        let value = nested.value_str().unwrap().as_str().to_string();
+        match name.as_str() {
+            "dialect" => {
+                assert!(dialect.is_none());
+                dialect = Some(value);
+            }
+            "phase" => {
+                assert!(phase.is_none());
+                phase = Some(value);
+            }
+            other => {
+                panic!("Unexpected key {}", other);
+            }
+        }
+    }
+
+    let Some(dialect) = dialect else {
+        assert!(phase.is_none());
+        return MirPhase::Built;
+    };
+
+    MirPhase::parse(dialect, phase)
+}
+
+struct ParseCtxt<'tcx, 'body> {
+    tcx: TyCtxt<'tcx>,
+    thir: &'body Thir<'tcx>,
+    source_info: SourceInfo,
+
+    body: &'body mut Body<'tcx>,
+    local_map: FxHashMap<LocalVarId, Local>,
+    block_map: FxHashMap<LocalVarId, BasicBlock>,
+}
+
+struct ParseError {
+    span: Span,
+    item_description: String,
+    expected: String,
+}
+
+impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
+    fn expr_error(&self, expr: ExprId, expected: &'static str) -> ParseError {
+        let expr = &self.thir[expr];
+        ParseError {
+            span: expr.span,
+            item_description: format!("{:?}", expr.kind),
+            expected: expected.to_string(),
+        }
+    }
+}
+
+type PResult<T> = Result<T, ParseError>;
diff --git a/compiler/rustc_mir_build/src/build/custom/parse.rs b/compiler/rustc_mir_build/src/build/custom/parse.rs
new file mode 100644
index 00000000000..52cb0a4826d
--- /dev/null
+++ b/compiler/rustc_mir_build/src/build/custom/parse.rs
@@ -0,0 +1,245 @@
+use rustc_index::vec::IndexVec;
+use rustc_middle::{mir::*, thir::*, ty::Ty};
+use rustc_span::Span;
+
+use super::{PResult, ParseCtxt, ParseError};
+
+mod instruction;
+
+/// Helper macro for parsing custom MIR.
+///
+/// Example usage looks something like:
+/// ```rust,ignore (incomplete example)
+/// parse_by_kind!(
+///     self, // : &ParseCtxt
+///     expr_id, // what you're matching against
+///     "assignment", // the thing you're trying to parse
+///     @call("mir_assign", args) => { args[0] }, // match invocations of the `mir_assign` special function
+///     ExprKind::Assign { lhs, .. } => { lhs }, // match thir assignment expressions
+///     // no need for fallthrough case - reasonable error is automatically generated
+/// )
+/// ```
+macro_rules! parse_by_kind {
+    (
+        $self:ident,
+        $expr_id:expr,
+        $expected:literal,
+        $(
+            @call($name:literal, $args:ident) => $call_expr:expr,
+        )*
+        $(
+            $pat:pat => $expr:expr,
+        )*
+    ) => {{
+        let expr_id = $self.preparse($expr_id);
+        let expr = &$self.thir[expr_id];
+        match &expr.kind {
+            $(
+                ExprKind::Call { ty, fun: _, args: $args, .. } if {
+                    match ty.kind() {
+                        ty::FnDef(did, _) => {
+                            $self.tcx.is_diagnostic_item(rustc_span::Symbol::intern($name), *did)
+                        }
+                        _ => false,
+                    }
+                } => $call_expr,
+            )*
+            $(
+                $pat => $expr,
+            )*
+            #[allow(unreachable_patterns)]
+            _ => return Err($self.expr_error(expr_id, $expected))
+        }
+    }};
+}
+pub(crate) use parse_by_kind;
+
+impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
+    /// Expressions should only ever be matched on after preparsing them. This removes extra scopes
+    /// we don't care about.
+    fn preparse(&self, expr_id: ExprId) -> ExprId {
+        let expr = &self.thir[expr_id];
+        match expr.kind {
+            ExprKind::Scope { value, .. } => self.preparse(value),
+            _ => expr_id,
+        }
+    }
+
+    fn statement_as_expr(&self, stmt_id: StmtId) -> PResult<ExprId> {
+        match &self.thir[stmt_id].kind {
+            StmtKind::Expr { expr, .. } => Ok(*expr),
+            kind @ StmtKind::Let { pattern, .. } => {
+                return Err(ParseError {
+                    span: pattern.span,
+                    item_description: format!("{:?}", kind),
+                    expected: "expression".to_string(),
+                });
+            }
+        }
+    }
+
+    pub fn parse_args(&mut self, params: &IndexVec<ParamId, Param<'tcx>>) -> PResult<()> {
+        for param in params.iter() {
+            let (var, span) = {
+                let pat = param.pat.as_ref().unwrap();
+                match &pat.kind {
+                    PatKind::Binding { var, .. } => (*var, pat.span),
+                    _ => {
+                        return Err(ParseError {
+                            span: pat.span,
+                            item_description: format!("{:?}", pat.kind),
+                            expected: "local".to_string(),
+                        });
+                    }
+                }
+            };
+            let decl = LocalDecl::new(param.ty, span);
+            let local = self.body.local_decls.push(decl);
+            self.local_map.insert(var, local);
+        }
+
+        Ok(())
+    }
+
+    /// Bodies are of the form:
+    ///
+    /// ```text
+    /// {
+    ///     let bb1: BasicBlock;
+    ///     let bb2: BasicBlock;
+    ///     {
+    ///         let RET: _;
+    ///         let local1;
+    ///         let local2;
+    ///
+    ///         {
+    ///             { // entry block
+    ///                 statement1;
+    ///                 terminator1
+    ///             };
+    ///
+    ///             bb1 = {
+    ///                 statement2;
+    ///                 terminator2
+    ///             };
+    ///
+    ///             bb2 = {
+    ///                 statement3;
+    ///                 terminator3
+    ///             }
+    ///
+    ///             RET
+    ///         }
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// This allows us to easily parse the basic blocks declarations, local declarations, and
+    /// basic block definitions in order.
+    pub fn parse_body(&mut self, expr_id: ExprId) -> PResult<()> {
+        let body = parse_by_kind!(self, expr_id, "whole body",
+            ExprKind::Block { block } => self.thir[*block].expr.unwrap(),
+        );
+        let (block_decls, rest) = parse_by_kind!(self, body, "body with block decls",
+            ExprKind::Block { block } => {
+                let block = &self.thir[*block];
+                (&block.stmts, block.expr.unwrap())
+            },
+        );
+        self.parse_block_decls(block_decls.iter().copied())?;
+
+        let (local_decls, rest) = parse_by_kind!(self, rest, "body with local decls",
+            ExprKind::Block { block } => {
+                let block = &self.thir[*block];
+                (&block.stmts, block.expr.unwrap())
+            },
+        );
+        self.parse_local_decls(local_decls.iter().copied())?;
+
+        let block_defs = parse_by_kind!(self, rest, "body with block defs",
+            ExprKind::Block { block } => &self.thir[*block].stmts,
+        );
+        for (i, block_def) in block_defs.iter().enumerate() {
+            let block = self.parse_block_def(self.statement_as_expr(*block_def)?)?;
+            self.body.basic_blocks_mut()[BasicBlock::from_usize(i)] = block;
+        }
+
+        Ok(())
+    }
+
+    fn parse_block_decls(&mut self, stmts: impl Iterator<Item = StmtId>) -> PResult<()> {
+        for stmt in stmts {
+            let (var, _, _) = self.parse_let_statement(stmt)?;
+            let data = BasicBlockData::new(None);
+            let block = self.body.basic_blocks_mut().push(data);
+            self.block_map.insert(var, block);
+        }
+
+        Ok(())
+    }
+
+    fn parse_local_decls(&mut self, mut stmts: impl Iterator<Item = StmtId>) -> PResult<()> {
+        let (ret_var, ..) = self.parse_let_statement(stmts.next().unwrap())?;
+        self.local_map.insert(ret_var, Local::from_u32(0));
+
+        for stmt in stmts {
+            let (var, ty, span) = self.parse_let_statement(stmt)?;
+            let decl = LocalDecl::new(ty, span);
+            let local = self.body.local_decls.push(decl);
+            self.local_map.insert(var, local);
+        }
+
+        Ok(())
+    }
+
+    fn parse_let_statement(&mut self, stmt_id: StmtId) -> PResult<(LocalVarId, Ty<'tcx>, Span)> {
+        let pattern = match &self.thir[stmt_id].kind {
+            StmtKind::Let { pattern, .. } => pattern,
+            StmtKind::Expr { expr, .. } => {
+                return Err(self.expr_error(*expr, "let statement"));
+            }
+        };
+
+        self.parse_var(pattern)
+    }
+
+    fn parse_var(&mut self, mut pat: &Pat<'tcx>) -> PResult<(LocalVarId, Ty<'tcx>, Span)> {
+        // Make sure we throw out any `AscribeUserType` we find
+        loop {
+            match &pat.kind {
+                PatKind::Binding { var, ty, .. } => break Ok((*var, *ty, pat.span)),
+                PatKind::AscribeUserType { subpattern, .. } => {
+                    pat = subpattern;
+                }
+                _ => {
+                    break Err(ParseError {
+                        span: pat.span,
+                        item_description: format!("{:?}", pat.kind),
+                        expected: "local".to_string(),
+                    });
+                }
+            }
+        }
+    }
+
+    fn parse_block_def(&self, expr_id: ExprId) -> PResult<BasicBlockData<'tcx>> {
+        let block = parse_by_kind!(self, expr_id, "basic block",
+            ExprKind::Block { block } => &self.thir[*block],
+        );
+
+        let mut data = BasicBlockData::new(None);
+        for stmt_id in &*block.stmts {
+            let stmt = self.statement_as_expr(*stmt_id)?;
+            let statement = self.parse_statement(stmt)?;
+            data.statements.push(Statement { source_info: self.source_info, kind: statement });
+        }
+
+        let Some(trailing) = block.expr else {
+            return Err(self.expr_error(expr_id, "terminator"))
+        };
+        let terminator = self.parse_terminator(trailing)?;
+        data.terminator = Some(Terminator { source_info: self.source_info, kind: terminator });
+
+        Ok(data)
+    }
+}
diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
new file mode 100644
index 00000000000..6d6176584f5
--- /dev/null
+++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
@@ -0,0 +1,72 @@
+use rustc_middle::{mir::*, thir::*, ty};
+
+use super::{parse_by_kind, PResult, ParseCtxt};
+
+impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
+    pub fn parse_statement(&self, expr_id: ExprId) -> PResult<StatementKind<'tcx>> {
+        parse_by_kind!(self, expr_id, "statement",
+            @call("mir_retag", args) => {
+                Ok(StatementKind::Retag(RetagKind::Default, Box::new(self.parse_place(args[0])?)))
+            },
+            @call("mir_retag_raw", args) => {
+                Ok(StatementKind::Retag(RetagKind::Raw, Box::new(self.parse_place(args[0])?)))
+            },
+            ExprKind::Assign { lhs, rhs } => {
+                let lhs = self.parse_place(*lhs)?;
+                let rhs = self.parse_rvalue(*rhs)?;
+                Ok(StatementKind::Assign(Box::new((lhs, rhs))))
+            },
+        )
+    }
+
+    pub fn parse_terminator(&self, expr_id: ExprId) -> PResult<TerminatorKind<'tcx>> {
+        parse_by_kind!(self, expr_id, "terminator",
+            @call("mir_return", _args) => {
+                Ok(TerminatorKind::Return)
+            },
+            @call("mir_goto", args) => {
+                Ok(TerminatorKind::Goto { target: self.parse_block(args[0])? } )
+            },
+        )
+    }
+
+    fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> {
+        parse_by_kind!(self, expr_id, "rvalue",
+            ExprKind::Borrow { borrow_kind, arg } => Ok(
+                Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?)
+            ),
+            ExprKind::AddressOf { mutability, arg } => Ok(
+                Rvalue::AddressOf(*mutability, self.parse_place(*arg)?)
+            ),
+            _ => self.parse_operand(expr_id).map(Rvalue::Use),
+        )
+    }
+
+    fn parse_operand(&self, expr_id: ExprId) -> PResult<Operand<'tcx>> {
+        parse_by_kind!(self, expr_id, "operand",
+            @call("mir_move", args) => self.parse_place(args[0]).map(Operand::Move),
+            _ => self.parse_place(expr_id).map(Operand::Copy),
+        )
+    }
+
+    fn parse_place(&self, expr_id: ExprId) -> PResult<Place<'tcx>> {
+        parse_by_kind!(self, expr_id, "place",
+            ExprKind::Deref { arg } => Ok(
+                self.parse_place(*arg)?.project_deeper(&[PlaceElem::Deref], self.tcx)
+            ),
+            _ => self.parse_local(expr_id).map(Place::from),
+        )
+    }
+
+    fn parse_local(&self, expr_id: ExprId) -> PResult<Local> {
+        parse_by_kind!(self, expr_id, "local",
+            ExprKind::VarRef { id } => Ok(self.local_map[id]),
+        )
+    }
+
+    fn parse_block(&self, expr_id: ExprId) -> PResult<BasicBlock> {
+        parse_by_kind!(self, expr_id, "basic block",
+            ExprKind::VarRef { id } => Ok(self.block_map[id]),
+        )
+    }
+}
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index cbcf9cd129f..437ac8d82a1 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -481,6 +481,22 @@ fn construct_fn<'tcx>(
         (None, fn_sig.output())
     };
 
+    if let Some(custom_mir_attr) =
+        tcx.hir().attrs(fn_id).iter().find(|attr| attr.name_or_empty() == sym::custom_mir)
+    {
+        return custom::build_custom_mir(
+            tcx,
+            fn_def.did.to_def_id(),
+            thir,
+            expr,
+            arguments,
+            return_ty,
+            return_ty_span,
+            span,
+            custom_mir_attr,
+        );
+    }
+
     let infcx = tcx.infer_ctxt().build();
     let mut builder = Builder::new(
         thir,
@@ -1033,6 +1049,7 @@ pub(crate) fn parse_float_into_scalar(
 
 mod block;
 mod cfg;
+mod custom;
 mod expr;
 mod matches;
 mod misc;
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index c7a7c3e3fa8..c4639d3a513 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -51,11 +51,17 @@ impl<'tcx> Cx<'tcx> {
         trace!(?expr.ty);
 
         // Now apply adjustments, if any.
-        for adjustment in self.typeck_results.expr_adjustments(hir_expr) {
-            trace!(?expr, ?adjustment);
-            let span = expr.span;
-            expr =
-                self.apply_adjustment(hir_expr, expr, adjustment, adjustment_span.unwrap_or(span));
+        if self.apply_adjustments {
+            for adjustment in self.typeck_results.expr_adjustments(hir_expr) {
+                trace!(?expr, ?adjustment);
+                let span = expr.span;
+                expr = self.apply_adjustment(
+                    hir_expr,
+                    expr,
+                    adjustment,
+                    adjustment_span.unwrap_or(span),
+                );
+            }
         }
 
         trace!(?expr.ty, "after adjustments");
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index 1d95d6b53fb..b5c4b7b137d 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -80,6 +80,9 @@ struct Cx<'tcx> {
     /// for the receiver.
     adjustment_span: Option<(HirId, Span)>,
 
+    /// False to indicate that adjustments should not be applied. Only used for `custom_mir`
+    apply_adjustments: bool,
+
     /// The `DefId` of the owner of this body.
     body_owner: DefId,
 }
@@ -87,6 +90,8 @@ struct Cx<'tcx> {
 impl<'tcx> Cx<'tcx> {
     fn new(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalDefId>) -> Cx<'tcx> {
         let typeck_results = tcx.typeck_opt_const_arg(def);
+        let did = def.did;
+        let hir = tcx.hir();
         Cx {
             tcx,
             thir: Thir::new(),
@@ -94,8 +99,12 @@ impl<'tcx> Cx<'tcx> {
             region_scope_tree: tcx.region_scope_tree(def.did),
             typeck_results,
             rvalue_scopes: &typeck_results.rvalue_scopes,
-            body_owner: def.did.to_def_id(),
+            body_owner: did.to_def_id(),
             adjustment_span: None,
+            apply_adjustments: hir
+                .attrs(hir.local_def_id_to_hir_id(did))
+                .iter()
+                .all(|attr| attr.name_or_empty() != rustc_span::sym::custom_mir),
         }
     }
 
diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs
index 269d9f3b102..e783d189137 100644
--- a/compiler/rustc_mir_transform/src/check_unsafety.rs
+++ b/compiler/rustc_mir_transform/src/check_unsafety.rs
@@ -471,6 +471,14 @@ fn unsafety_check_result<'tcx>(
     // `mir_built` force this.
     let body = &tcx.mir_built(def).borrow();
 
+    if body.should_skip() {
+        return tcx.arena.alloc(UnsafetyCheckResult {
+            violations: Vec::new(),
+            used_unsafe_blocks: FxHashSet::default(),
+            unused_unsafes: Some(Vec::new()),
+        });
+    }
+
     let param_env = tcx.param_env(def.did);
 
     let mut checker = UnsafetyChecker::new(body, def.did, tcx, param_env);
diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs
index 230c6a7cb4b..27dbc3e22c9 100644
--- a/compiler/rustc_mir_transform/src/pass_manager.rs
+++ b/compiler/rustc_mir_transform/src/pass_manager.rs
@@ -96,45 +96,48 @@ fn run_passes_inner<'tcx>(
     phase_change: Option<MirPhase>,
     validate_each: bool,
 ) {
-    let validate = validate_each & tcx.sess.opts.unstable_opts.validate_mir;
+    let validate = validate_each & tcx.sess.opts.unstable_opts.validate_mir & !body.should_skip();
     let overridden_passes = &tcx.sess.opts.unstable_opts.mir_enable_passes;
     trace!(?overridden_passes);
 
-    for pass in passes {
-        let name = pass.name();
-
-        let overridden =
-            overridden_passes.iter().rev().find(|(s, _)| s == &*name).map(|(_name, polarity)| {
-                trace!(
-                    pass = %name,
-                    "{} as requested by flag",
-                    if *polarity { "Running" } else { "Not running" },
-                );
-                *polarity
-            });
-        if !overridden.unwrap_or_else(|| pass.is_enabled(&tcx.sess)) {
-            continue;
+    if !body.should_skip() {
+        for pass in passes {
+            let name = pass.name();
+
+            let overridden = overridden_passes.iter().rev().find(|(s, _)| s == &*name).map(
+                |(_name, polarity)| {
+                    trace!(
+                        pass = %name,
+                        "{} as requested by flag",
+                        if *polarity { "Running" } else { "Not running" },
+                    );
+                    *polarity
+                },
+            );
+            if !overridden.unwrap_or_else(|| pass.is_enabled(&tcx.sess)) {
+                continue;
+            }
+
+            let dump_enabled = pass.is_mir_dump_enabled();
+
+            if dump_enabled {
+                dump_mir_for_pass(tcx, body, &name, false);
+            }
+            if validate {
+                validate_body(tcx, body, format!("before pass {}", name));
+            }
+
+            pass.run_pass(tcx, body);
+
+            if dump_enabled {
+                dump_mir_for_pass(tcx, body, &name, true);
+            }
+            if validate {
+                validate_body(tcx, body, format!("after pass {}", name));
+            }
+
+            body.pass_count += 1;
         }
-
-        let dump_enabled = pass.is_mir_dump_enabled();
-
-        if dump_enabled {
-            dump_mir_for_pass(tcx, body, &name, false);
-        }
-        if validate {
-            validate_body(tcx, body, format!("before pass {}", name));
-        }
-
-        pass.run_pass(tcx, body);
-
-        if dump_enabled {
-            dump_mir_for_pass(tcx, body, &name, true);
-        }
-        if validate {
-            validate_body(tcx, body, format!("after pass {}", name));
-        }
-
-        body.pass_count += 1;
     }
 
     if let Some(new_phase) = phase_change {
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index cccc4897ecc..54a61483a11 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -584,6 +584,7 @@ symbols! {
         custom_attribute,
         custom_derive,
         custom_inner_attributes,
+        custom_mir,
         custom_test_frameworks,
         d,
         d32,
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
index 6d919a4c2ad..0f6bbc32317 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
@@ -1,26 +1,25 @@
+use super::apple_base::{macos_link_env_remove, macos_llvm_target, opts, Arch};
 use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let arch = "arm64";
-    let mut base = super::apple_base::opts("macos", arch, "");
+    let arch = Arch::Arm64;
+    let mut base = opts("macos", arch);
     base.cpu = "apple-a14".into();
     base.max_atomic_width = Some(128);
 
     // FIXME: The leak sanitizer currently fails the tests, see #88132.
     base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD;
 
-    base.link_env_remove.to_mut().extend(super::apple_base::macos_link_env_remove());
-
-    // Clang automatically chooses a more specific target based on
-    // MACOSX_DEPLOYMENT_TARGET.  To enable cross-language LTO to work
-    // correctly, we do too.
-    let llvm_target = super::apple_base::macos_llvm_target(arch);
+    base.link_env_remove.to_mut().extend(macos_link_env_remove());
 
     Target {
-        llvm_target: llvm_target.into(),
+        // Clang automatically chooses a more specific target based on
+        // MACOSX_DEPLOYMENT_TARGET.  To enable cross-language LTO to work
+        // correctly, we do too.
+        llvm_target: macos_llvm_target(arch).into(),
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(),
-        arch: "aarch64".into(),
+        arch: arch.target_arch(),
         options: TargetOptions {
             mcount: "\u{1}mcount".into(),
             frame_pointer: FramePointer::NonLeaf,
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs
index beb9042390b..b5f9eb1259d 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs
@@ -1,19 +1,17 @@
-use super::apple_sdk_base::{opts, Arch};
+use super::apple_base::{ios_llvm_target, opts, Arch};
 use crate::spec::{FramePointer, Target, TargetOptions};
 
 pub fn target() -> Target {
-    // Clang automatically chooses a more specific target based on
-    // IPHONEOS_DEPLOYMENT_TARGET.
-    // This is required for the target to pick the right
-    // MACH-O commands, so we do too.
-    let arch = "arm64";
-    let llvm_target = super::apple_base::ios_llvm_target(arch);
-
+    let arch = Arch::Arm64;
     Target {
-        llvm_target: llvm_target.into(),
+        // Clang automatically chooses a more specific target based on
+        // IPHONEOS_DEPLOYMENT_TARGET.
+        // This is required for the target to pick the right
+        // MACH-O commands, so we do too.
+        llvm_target: ios_llvm_target(arch).into(),
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(),
-        arch: "aarch64".into(),
+        arch: arch.target_arch(),
         options: TargetOptions {
             features: "+neon,+fp-armv8,+apple-a7".into(),
             max_atomic_width: Some(128),
@@ -30,7 +28,7 @@ pub fn target() -> Target {
                 darwinpcs\0\
                 -Os\0"
                 .into(),
-            ..opts("ios", Arch::Arm64)
+            ..opts("ios", arch)
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs
index 2d2671549cf..0009972cf42 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs
@@ -1,17 +1,18 @@
-use super::apple_sdk_base::{opts, Arch};
+use super::apple_base::{opts, Arch};
 use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, Target, TargetOptions};
 
 pub fn target() -> Target {
     let llvm_target = "arm64-apple-ios14.0-macabi";
 
-    let mut base = opts("ios", Arch::Arm64_macabi);
+    let arch = Arch::Arm64_macabi;
+    let mut base = opts("ios", arch);
     base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-target", llvm_target]);
 
     Target {
         llvm_target: llvm_target.into(),
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(),
-        arch: "aarch64".into(),
+        arch: arch.target_arch(),
         options: TargetOptions {
             features: "+neon,+fp-armv8,+apple-a12".into(),
             max_atomic_width: Some(128),
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios_sim.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios_sim.rs
index b4e135f66e9..3374755e2dd 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_ios_sim.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_ios_sim.rs
@@ -1,21 +1,17 @@
-use super::apple_sdk_base::{opts, Arch};
+use super::apple_base::{ios_sim_llvm_target, opts, Arch};
 use crate::spec::{FramePointer, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts("ios", Arch::Arm64_sim);
-
-    // Clang automatically chooses a more specific target based on
-    // IPHONEOS_DEPLOYMENT_TARGET.
-    // This is required for the simulator target to pick the right
-    // MACH-O commands, so we do too.
-    let arch = "arm64";
-    let llvm_target = super::apple_base::ios_sim_llvm_target(arch);
-
+    let arch = Arch::Arm64_sim;
     Target {
-        llvm_target: llvm_target.into(),
+        // Clang automatically chooses a more specific target based on
+        // IPHONEOS_DEPLOYMENT_TARGET.
+        // This is required for the simulator target to pick the right
+        // MACH-O commands, so we do too.
+        llvm_target: ios_sim_llvm_target(arch).into(),
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(),
-        arch: "aarch64".into(),
+        arch: arch.target_arch(),
         options: TargetOptions {
             features: "+neon,+fp-armv8,+apple-a7".into(),
             max_atomic_width: Some(128),
@@ -32,7 +28,7 @@ pub fn target() -> Target {
                 darwinpcs\0\
                 -Os\0"
                 .into(),
-            ..base
+            ..opts("ios", arch)
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs b/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs
index 2e31d16dc76..bb7c39ff26b 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs
@@ -1,18 +1,19 @@
-use super::apple_sdk_base::{opts, Arch};
+use super::apple_base::{opts, Arch};
 use crate::spec::{FramePointer, Target, TargetOptions};
 
 pub fn target() -> Target {
+    let arch = Arch::Arm64;
     Target {
         llvm_target: "arm64-apple-tvos".into(),
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(),
-        arch: "aarch64".into(),
+        arch: arch.target_arch(),
         options: TargetOptions {
             features: "+neon,+fp-armv8,+apple-a7".into(),
             max_atomic_width: Some(128),
             forces_embed_bitcode: true,
             frame_pointer: FramePointer::NonLeaf,
-            ..opts("tvos", Arch::Arm64)
+            ..opts("tvos", arch)
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_watchos_sim.rs b/compiler/rustc_target/src/spec/aarch64_apple_watchos_sim.rs
index 3059f42140b..e4af4127c22 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_watchos_sim.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_watchos_sim.rs
@@ -1,21 +1,17 @@
-use super::apple_sdk_base::{opts, Arch};
+use super::apple_base::{opts, watchos_sim_llvm_target, Arch};
 use crate::spec::{FramePointer, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts("watchos", Arch::Arm64_sim);
-
-    // Clang automatically chooses a more specific target based on
-    // WATCHOS_DEPLOYMENT_TARGET.
-    // This is required for the simulator target to pick the right
-    // MACH-O commands, so we do too.
-    let arch = "arm64";
-    let llvm_target = super::apple_base::watchos_sim_llvm_target(arch);
-
+    let arch = Arch::Arm64_sim;
     Target {
-        llvm_target: llvm_target.into(),
+        // Clang automatically chooses a more specific target based on
+        // WATCHOS_DEPLOYMENT_TARGET.
+        // This is required for the simulator target to pick the right
+        // MACH-O commands, so we do too.
+        llvm_target: watchos_sim_llvm_target(arch).into(),
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(),
-        arch: "aarch64".into(),
+        arch: arch.target_arch(),
         options: TargetOptions {
             features: "+neon,+fp-armv8,+apple-a7".into(),
             max_atomic_width: Some(128),
@@ -32,7 +28,7 @@ pub fn target() -> Target {
                 darwinpcs\0\
                 -Os\0"
                 .into(),
-            ..base
+            ..opts("watchos", arch)
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs
index 40bc59ca145..23c826cb1bd 100644
--- a/compiler/rustc_target/src/spec/apple_base.rs
+++ b/compiler/rustc_target/src/spec/apple_base.rs
@@ -3,7 +3,88 @@ use std::{borrow::Cow, env};
 use crate::spec::{cvs, Cc, DebuginfoKind, FramePointer, LinkArgs};
 use crate::spec::{LinkerFlavor, Lld, SplitDebuginfo, StaticCow, TargetOptions};
 
-fn pre_link_args(os: &'static str, arch: &'static str, abi: &'static str) -> LinkArgs {
+#[cfg(test)]
+#[path = "apple/tests.rs"]
+mod tests;
+
+use Arch::*;
+#[allow(non_camel_case_types)]
+#[derive(Copy, Clone)]
+pub enum Arch {
+    Armv7,
+    Armv7k,
+    Armv7s,
+    Arm64,
+    Arm64_32,
+    I386,
+    I686,
+    X86_64,
+    X86_64_sim,
+    X86_64_macabi,
+    Arm64_macabi,
+    Arm64_sim,
+}
+
+impl Arch {
+    pub fn target_name(self) -> &'static str {
+        match self {
+            Armv7 => "armv7",
+            Armv7k => "armv7k",
+            Armv7s => "armv7s",
+            Arm64 | Arm64_macabi | Arm64_sim => "arm64",
+            Arm64_32 => "arm64_32",
+            I386 => "i386",
+            I686 => "i686",
+            X86_64 | X86_64_sim | X86_64_macabi => "x86_64",
+        }
+    }
+
+    pub fn target_arch(self) -> Cow<'static, str> {
+        Cow::Borrowed(match self {
+            Armv7 | Armv7k | Armv7s => "arm",
+            Arm64 | Arm64_32 | Arm64_macabi | Arm64_sim => "aarch64",
+            I386 | I686 => "x86",
+            X86_64 | X86_64_sim | X86_64_macabi => "x86_64",
+        })
+    }
+
+    fn target_abi(self) -> &'static str {
+        match self {
+            Armv7 | Armv7k | Armv7s | Arm64 | Arm64_32 | I386 | I686 | X86_64 => "",
+            X86_64_macabi | Arm64_macabi => "macabi",
+            // x86_64-apple-ios is a simulator target, even though it isn't
+            // declared that way in the target like the other ones...
+            Arm64_sim | X86_64_sim => "sim",
+        }
+    }
+
+    fn target_cpu(self) -> &'static str {
+        match self {
+            Armv7 => "cortex-a8", // iOS7 is supported on iPhone 4 and higher
+            Armv7k => "cortex-a8",
+            Armv7s => "cortex-a9",
+            Arm64 => "apple-a7",
+            Arm64_32 => "apple-s4",
+            I386 | I686 => "yonah",
+            X86_64 | X86_64_sim => "core2",
+            X86_64_macabi => "core2",
+            Arm64_macabi => "apple-a12",
+            Arm64_sim => "apple-a12",
+        }
+    }
+
+    fn link_env_remove(self) -> StaticCow<[StaticCow<str>]> {
+        match self {
+            Armv7 | Armv7k | Armv7s | Arm64 | Arm64_32 | I386 | I686 | X86_64 | X86_64_sim
+            | Arm64_sim => {
+                cvs!["MACOSX_DEPLOYMENT_TARGET"]
+            }
+            X86_64_macabi | Arm64_macabi => cvs!["IPHONEOS_DEPLOYMENT_TARGET"],
+        }
+    }
+}
+
+fn pre_link_args(os: &'static str, arch: Arch, abi: &'static str) -> LinkArgs {
     let platform_name: StaticCow<str> = match abi {
         "sim" => format!("{}-simulator", os).into(),
         "macabi" => "mac-catalyst".into(),
@@ -19,6 +100,8 @@ fn pre_link_args(os: &'static str, arch: &'static str, abi: &'static str) -> Lin
     }
     .into();
 
+    let arch = arch.target_name();
+
     let mut args = TargetOptions::link_args(
         LinkerFlavor::Darwin(Cc::No, Lld::No),
         &["-arch", arch, "-platform_version"],
@@ -35,24 +118,29 @@ fn pre_link_args(os: &'static str, arch: &'static str, abi: &'static str) -> Lin
     args
 }
 
-pub fn opts(os: &'static str, arch: &'static str, abi: &'static str) -> TargetOptions {
-    // ELF TLS is only available in macOS 10.7+. If you try to compile for 10.6
+pub fn opts(os: &'static str, arch: Arch) -> TargetOptions {
+    // Static TLS is only available in macOS 10.7+. If you try to compile for 10.6
     // either the linker will complain if it is used or the binary will end up
     // segfaulting at runtime when run on 10.6. Rust by default supports macOS
     // 10.7+, but there is a standard environment variable,
     // MACOSX_DEPLOYMENT_TARGET, which is used to signal targeting older
     // versions of macOS. For example compiling on 10.10 with
     // MACOSX_DEPLOYMENT_TARGET set to 10.6 will cause the linker to generate
-    // warnings about the usage of ELF TLS.
+    // warnings about the usage of static TLS.
     //
-    // Here we detect what version is being requested, defaulting to 10.7. ELF
+    // Here we detect what version is being requested, defaulting to 10.7. Static
     // TLS is flagged as enabled if it looks to be supported. The architecture
     // only matters for default deployment target which is 11.0 for ARM64 and
     // 10.7 for everything else.
-    let has_thread_local = macos_deployment_target("x86_64") >= (10, 7);
+    let has_thread_local = os == "macos" && macos_deployment_target(Arch::X86_64) >= (10, 7);
+
+    let abi = arch.target_abi();
 
     TargetOptions {
+        abi: abi.into(),
         os: os.into(),
+        cpu: arch.target_cpu().into(),
+        link_env_remove: arch.link_env_remove(),
         vendor: "apple".into(),
         linker_flavor: LinkerFlavor::Darwin(Cc::Yes, Lld::No),
         // macOS has -dead_strip, which doesn't rely on function_sections
@@ -103,23 +191,24 @@ fn deployment_target(var_name: &str) -> Option<(u32, u32)> {
         .and_then(|(a, b)| a.parse::<u32>().and_then(|a| b.parse::<u32>().map(|b| (a, b))).ok())
 }
 
-fn macos_default_deployment_target(arch: &str) -> (u32, u32) {
-    if arch == "arm64" { (11, 0) } else { (10, 7) }
+fn macos_default_deployment_target(arch: Arch) -> (u32, u32) {
+    // Note: Arm64_sim is not included since macOS has no simulator.
+    if matches!(arch, Arm64 | Arm64_macabi) { (11, 0) } else { (10, 7) }
 }
 
-fn macos_deployment_target(arch: &str) -> (u32, u32) {
+fn macos_deployment_target(arch: Arch) -> (u32, u32) {
     deployment_target("MACOSX_DEPLOYMENT_TARGET")
         .unwrap_or_else(|| macos_default_deployment_target(arch))
 }
 
-fn macos_lld_platform_version(arch: &str) -> String {
+fn macos_lld_platform_version(arch: Arch) -> String {
     let (major, minor) = macos_deployment_target(arch);
     format!("{}.{}", major, minor)
 }
 
-pub fn macos_llvm_target(arch: &str) -> String {
+pub fn macos_llvm_target(arch: Arch) -> String {
     let (major, minor) = macos_deployment_target(arch);
-    format!("{}-apple-macosx{}.{}.0", arch, major, minor)
+    format!("{}-apple-macosx{}.{}.0", arch.target_name(), major, minor)
 }
 
 pub fn macos_link_env_remove() -> Vec<StaticCow<str>> {
@@ -142,7 +231,7 @@ fn ios_deployment_target() -> (u32, u32) {
     deployment_target("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or((7, 0))
 }
 
-pub fn ios_llvm_target(arch: &str) -> String {
+pub fn ios_llvm_target(arch: Arch) -> String {
     // Modern iOS tooling extracts information about deployment target
     // from LC_BUILD_VERSION. This load command will only be emitted when
     // we build with a version specific `llvm_target`, with the version
@@ -150,7 +239,7 @@ pub fn ios_llvm_target(arch: &str) -> String {
     // to pick it up (since std and core are still built with the fallback
     // of version 7.0 and hence emit the old LC_IPHONE_MIN_VERSION).
     let (major, minor) = ios_deployment_target();
-    format!("{}-apple-ios{}.{}.0", arch, major, minor)
+    format!("{}-apple-ios{}.{}.0", arch.target_name(), major, minor)
 }
 
 fn ios_lld_platform_version() -> String {
@@ -158,9 +247,9 @@ fn ios_lld_platform_version() -> String {
     format!("{}.{}", major, minor)
 }
 
-pub fn ios_sim_llvm_target(arch: &str) -> String {
+pub fn ios_sim_llvm_target(arch: Arch) -> String {
     let (major, minor) = ios_deployment_target();
-    format!("{}-apple-ios{}.{}.0-simulator", arch, major, minor)
+    format!("{}-apple-ios{}.{}.0-simulator", arch.target_name(), major, minor)
 }
 
 fn tvos_deployment_target() -> (u32, u32) {
@@ -181,7 +270,7 @@ fn watchos_lld_platform_version() -> String {
     format!("{}.{}", major, minor)
 }
 
-pub fn watchos_sim_llvm_target(arch: &str) -> String {
+pub fn watchos_sim_llvm_target(arch: Arch) -> String {
     let (major, minor) = watchos_deployment_target();
-    format!("{}-apple-watchos{}.{}.0-simulator", arch, major, minor)
+    format!("{}-apple-watchos{}.{}.0-simulator", arch.target_name(), major, minor)
 }
diff --git a/compiler/rustc_target/src/spec/apple_sdk_base.rs b/compiler/rustc_target/src/spec/apple_sdk_base.rs
deleted file mode 100644
index 148031b1569..00000000000
--- a/compiler/rustc_target/src/spec/apple_sdk_base.rs
+++ /dev/null
@@ -1,81 +0,0 @@
-use crate::spec::{cvs, TargetOptions};
-use std::borrow::Cow;
-
-#[cfg(test)]
-#[path = "apple/tests.rs"]
-mod tests;
-
-use Arch::*;
-#[allow(non_camel_case_types)]
-#[derive(Copy, Clone)]
-pub enum Arch {
-    Armv7,
-    Armv7k,
-    Armv7s,
-    Arm64,
-    Arm64_32,
-    I386,
-    #[allow(dead_code)] // Some targets don't use this enum...
-    X86_64,
-    X86_64_sim,
-    X86_64_macabi,
-    Arm64_macabi,
-    Arm64_sim,
-}
-
-fn target_arch_name(arch: Arch) -> &'static str {
-    match arch {
-        Armv7 => "armv7",
-        Armv7k => "armv7k",
-        Armv7s => "armv7s",
-        Arm64 | Arm64_macabi | Arm64_sim => "arm64",
-        Arm64_32 => "arm64_32",
-        I386 => "i386",
-        X86_64 | X86_64_sim | X86_64_macabi => "x86_64",
-    }
-}
-
-fn target_abi(arch: Arch) -> &'static str {
-    match arch {
-        Armv7 | Armv7k | Armv7s | Arm64 | Arm64_32 | I386 | X86_64 => "",
-        X86_64_macabi | Arm64_macabi => "macabi",
-        // x86_64-apple-ios is a simulator target, even though it isn't
-        // declared that way in the target like the other ones...
-        Arm64_sim | X86_64_sim => "sim",
-    }
-}
-
-fn target_cpu(arch: Arch) -> &'static str {
-    match arch {
-        Armv7 => "cortex-a8", // iOS7 is supported on iPhone 4 and higher
-        Armv7k => "cortex-a8",
-        Armv7s => "cortex-a9",
-        Arm64 => "apple-a7",
-        Arm64_32 => "apple-s4",
-        I386 => "yonah",
-        X86_64 | X86_64_sim => "core2",
-        X86_64_macabi => "core2",
-        Arm64_macabi => "apple-a12",
-        Arm64_sim => "apple-a12",
-    }
-}
-
-fn link_env_remove(arch: Arch) -> Cow<'static, [Cow<'static, str>]> {
-    match arch {
-        Armv7 | Armv7k | Armv7s | Arm64 | Arm64_32 | I386 | X86_64 | X86_64_sim | Arm64_sim => {
-            cvs!["MACOSX_DEPLOYMENT_TARGET"]
-        }
-        X86_64_macabi | Arm64_macabi => cvs!["IPHONEOS_DEPLOYMENT_TARGET"],
-    }
-}
-
-pub fn opts(os: &'static str, arch: Arch) -> TargetOptions {
-    let abi = target_abi(arch);
-    TargetOptions {
-        abi: abi.into(),
-        cpu: target_cpu(arch).into(),
-        link_env_remove: link_env_remove(arch),
-        has_thread_local: false,
-        ..super::apple_base::opts(os, target_arch_name(arch), abi)
-    }
-}
diff --git a/compiler/rustc_target/src/spec/arm64_32_apple_watchos.rs b/compiler/rustc_target/src/spec/arm64_32_apple_watchos.rs
index cb7f5f2a583..2cf2cbc7510 100644
--- a/compiler/rustc_target/src/spec/arm64_32_apple_watchos.rs
+++ b/compiler/rustc_target/src/spec/arm64_32_apple_watchos.rs
@@ -1,4 +1,4 @@
-use super::apple_sdk_base::{opts, Arch};
+use super::apple_base::{opts, Arch};
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
diff --git a/compiler/rustc_target/src/spec/armv7_apple_ios.rs b/compiler/rustc_target/src/spec/armv7_apple_ios.rs
index 57fd74a36b6..3259c854791 100644
--- a/compiler/rustc_target/src/spec/armv7_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/armv7_apple_ios.rs
@@ -1,18 +1,21 @@
-use super::apple_sdk_base::{opts, Arch};
+use super::apple_base::{ios_llvm_target, opts, Arch};
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let llvm_target = super::apple_base::ios_llvm_target("armv7");
-
+    let arch = Arch::Armv7;
     Target {
-        llvm_target: llvm_target.into(),
+        // Clang automatically chooses a more specific target based on
+        // IPHONEOS_DEPLOYMENT_TARGET.
+        // This is required for the target to pick the right
+        // MACH-O commands, so we do too.
+        llvm_target: ios_llvm_target(arch).into(),
         pointer_width: 32,
         data_layout: "e-m:o-p:32:32-Fi8-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32".into(),
-        arch: "arm".into(),
+        arch: arch.target_arch(),
         options: TargetOptions {
             features: "+v7,+vfp3,+neon".into(),
             max_atomic_width: Some(64),
-            ..opts("ios", Arch::Armv7)
+            ..opts("ios", arch)
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/armv7k_apple_watchos.rs b/compiler/rustc_target/src/spec/armv7k_apple_watchos.rs
index af5d1c2ff45..45ead8d65ab 100644
--- a/compiler/rustc_target/src/spec/armv7k_apple_watchos.rs
+++ b/compiler/rustc_target/src/spec/armv7k_apple_watchos.rs
@@ -1,13 +1,13 @@
-use super::apple_sdk_base::{opts, Arch};
+use super::apple_base::{opts, Arch};
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts("watchos", Arch::Armv7k);
+    let arch = Arch::Armv7k;
     Target {
         llvm_target: "armv7k-apple-watchos".into(),
         pointer_width: 32,
         data_layout: "e-m:o-p:32:32-Fi8-i64:64-a:0:32-n32-S128".into(),
-        arch: "arm".into(),
+        arch: arch.target_arch(),
         options: TargetOptions {
             features: "+v7,+vfp4,+neon".into(),
             max_atomic_width: Some(64),
@@ -22,7 +22,7 @@ pub fn target() -> Target {
                 darwinpcs\0\
                 -Os\0"
                 .into(),
-            ..base
+            ..opts("watchos", arch)
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/armv7s_apple_ios.rs b/compiler/rustc_target/src/spec/armv7s_apple_ios.rs
index cc17265b2b8..be4bc675844 100644
--- a/compiler/rustc_target/src/spec/armv7s_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/armv7s_apple_ios.rs
@@ -1,16 +1,17 @@
-use super::apple_sdk_base::{opts, Arch};
+use super::apple_base::{opts, Arch};
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
+    let arch = Arch::Armv7s;
     Target {
         llvm_target: "armv7s-apple-ios".into(),
         pointer_width: 32,
         data_layout: "e-m:o-p:32:32-Fi8-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32".into(),
-        arch: "arm".into(),
+        arch: arch.target_arch(),
         options: TargetOptions {
             features: "+v7,+vfp4,+neon".into(),
             max_atomic_width: Some(64),
-            ..opts("ios", Arch::Armv7s)
+            ..opts("ios", arch)
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/i386_apple_ios.rs b/compiler/rustc_target/src/spec/i386_apple_ios.rs
index b85214a9c6b..5819981612e 100644
--- a/compiler/rustc_target/src/spec/i386_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/i386_apple_ios.rs
@@ -1,21 +1,23 @@
-use super::apple_sdk_base::{opts, Arch};
+use super::apple_base::{ios_sim_llvm_target, opts, Arch};
 use crate::spec::{StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts("ios", Arch::I386);
-    let llvm_target = super::apple_base::ios_sim_llvm_target("i386");
-
+    let arch = Arch::I386;
     Target {
-        llvm_target: llvm_target.into(),
+        // Clang automatically chooses a more specific target based on
+        // IPHONEOS_DEPLOYMENT_TARGET.
+        // This is required for the target to pick the right
+        // MACH-O commands, so we do too.
+        llvm_target: ios_sim_llvm_target(arch).into(),
         pointer_width: 32,
         data_layout: "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             f64:32:64-f80:128-n8:16:32-S128"
             .into(),
-        arch: "x86".into(),
+        arch: arch.target_arch(),
         options: TargetOptions {
             max_atomic_width: Some(64),
             stack_probes: StackProbeType::X86,
-            ..base
+            ..opts("ios", arch)
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/i686_apple_darwin.rs
index 15607c12ea9..8b968af5ecc 100644
--- a/compiler/rustc_target/src/spec/i686_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/i686_apple_darwin.rs
@@ -1,28 +1,28 @@
+use super::apple_base::{macos_link_env_remove, macos_llvm_target, opts, Arch};
 use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
-    // ld64 only understand i386 and not i686
-    let mut base = super::apple_base::opts("macos", "i386", "");
-    base.cpu = "yonah".into();
+    // ld64 only understands i386 and not i686
+    let arch = Arch::I386;
+    let mut base = opts("macos", arch);
     base.max_atomic_width = Some(64);
     base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-m32"]);
-    base.link_env_remove.to_mut().extend(super::apple_base::macos_link_env_remove());
+    base.link_env_remove.to_mut().extend(macos_link_env_remove());
     base.stack_probes = StackProbeType::X86;
     base.frame_pointer = FramePointer::Always;
 
-    // Clang automatically chooses a more specific target based on
-    // MACOSX_DEPLOYMENT_TARGET.  To enable cross-language LTO to work
-    // correctly, we do too.
-    let arch = "i686";
-    let llvm_target = super::apple_base::macos_llvm_target(&arch);
-
     Target {
-        llvm_target: llvm_target.into(),
+        // Clang automatically chooses a more specific target based on
+        // MACOSX_DEPLOYMENT_TARGET.  To enable cross-language LTO to work
+        // correctly, we do too.
+        //
+        // While ld64 doesn't understand i686, LLVM does.
+        llvm_target: macos_llvm_target(Arch::I686).into(),
         pointer_width: 32,
         data_layout: "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             f64:32:64-f80:128-n8:16:32-S128"
             .into(),
-        arch: "x86".into(),
+        arch: arch.target_arch(),
         options: TargetOptions { mcount: "\u{1}mcount".into(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/linux_kernel_base.rs b/compiler/rustc_target/src/spec/linux_kernel_base.rs
deleted file mode 100644
index f41533a9548..00000000000
--- a/compiler/rustc_target/src/spec/linux_kernel_base.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-use crate::spec::TargetOptions;
-use crate::spec::{FramePointer, PanicStrategy, RelocModel, RelroLevel, StackProbeType};
-
-pub fn opts() -> TargetOptions {
-    TargetOptions {
-        env: "gnu".into(),
-        disable_redzone: true,
-        panic_strategy: PanicStrategy::Abort,
-        stack_probes: StackProbeType::X86,
-        frame_pointer: FramePointer::Always,
-        position_independent_executables: true,
-        needs_plt: true,
-        relro_level: RelroLevel::Full,
-        relocation_model: RelocModel::Static,
-
-        ..Default::default()
-    }
-}
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 72b088d663b..1bcb02ecb30 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -59,7 +59,6 @@ pub mod crt_objects;
 
 mod android_base;
 mod apple_base;
-mod apple_sdk_base;
 mod avr_gnu_base;
 mod bpf_base;
 mod dragonfly_base;
@@ -71,7 +70,6 @@ mod illumos_base;
 mod l4re_base;
 mod linux_base;
 mod linux_gnu_base;
-mod linux_kernel_base;
 mod linux_musl_base;
 mod linux_uclibc_base;
 mod msvc_base;
@@ -1003,7 +1001,7 @@ macro_rules! supported_targets {
             $(
                 #[test] // `#[test]`
                 fn $module() {
-                    tests_impl::test_target(super::$module::target(), $triple);
+                    tests_impl::test_target(super::$module::target());
                 }
             )+
         }
@@ -1071,8 +1069,6 @@ supported_targets! {
     ("thumbv7neon-linux-androideabi", thumbv7neon_linux_androideabi),
     ("aarch64-linux-android", aarch64_linux_android),
 
-    ("x86_64-unknown-none-linuxkernel", x86_64_unknown_none_linuxkernel),
-
     ("aarch64-unknown-freebsd", aarch64_unknown_freebsd),
     ("armv6-unknown-freebsd", armv6_unknown_freebsd),
     ("armv7-unknown-freebsd", armv7_unknown_freebsd),
@@ -1941,8 +1937,10 @@ impl Target {
             | PlatformIntrinsic
             | Unadjusted
             | Cdecl { .. }
-            | EfiApi
             | RustCold => true,
+            EfiApi => {
+                ["arm", "aarch64", "riscv32", "riscv64", "x86", "x86_64"].contains(&&self.arch[..])
+            }
             X86Interrupt => ["x86", "x86_64"].contains(&&self.arch[..]),
             Aapcs { .. } => "arm" == self.arch,
             CCmseNonSecureCall => ["arm", "aarch64"].contains(&&self.arch[..]),
diff --git a/compiler/rustc_target/src/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs
index 172da0ed5df..e0ecf8037c3 100644
--- a/compiler/rustc_target/src/spec/tests/tests_impl.rs
+++ b/compiler/rustc_target/src/spec/tests/tests_impl.rs
@@ -2,15 +2,15 @@ use super::super::*;
 use std::assert_matches::assert_matches;
 
 // Test target self-consistency and JSON encoding/decoding roundtrip.
-pub(super) fn test_target(mut target: Target, triple: &str) {
+pub(super) fn test_target(mut target: Target) {
     let recycled_target = Target::from_json(target.to_json()).map(|(j, _)| j);
     target.update_to_cli();
-    target.check_consistency(triple);
+    target.check_consistency();
     assert_eq!(recycled_target, Ok(target));
 }
 
 impl Target {
-    fn check_consistency(&self, triple: &str) {
+    fn check_consistency(&self) {
         assert_eq!(self.is_like_osx, self.vendor == "apple");
         assert_eq!(self.is_like_solaris, self.os == "solaris" || self.os == "illumos");
         assert_eq!(self.is_like_windows, self.os == "windows" || self.os == "uefi");
@@ -129,8 +129,7 @@ impl Target {
         if self.dynamic_linking && !(self.is_like_wasm && self.os != "emscripten") {
             assert_eq!(self.relocation_model, RelocModel::Pic);
         }
-        // PIEs are supported but not enabled by default with linuxkernel target.
-        if self.position_independent_executables && !triple.ends_with("-linuxkernel") {
+        if self.position_independent_executables {
             assert_eq!(self.relocation_model, RelocModel::Pic);
         }
         // The UEFI targets do not support dynamic linking but still require PIC (#101377).
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
index 087be1b957b..c053031612c 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
@@ -1,29 +1,27 @@
+use super::apple_base::{macos_link_env_remove, macos_llvm_target, opts, Arch};
 use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, SanitizerSet};
 use crate::spec::{StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let arch = "x86_64";
-    let mut base = super::apple_base::opts("macos", arch, "");
-    base.cpu = "core2".into();
-    base.max_atomic_width = Some(128); // core2 support cmpxchg16b
+    let arch = Arch::X86_64;
+    let mut base = opts("macos", arch);
+    base.max_atomic_width = Some(128); // core2 supports cmpxchg16b
     base.frame_pointer = FramePointer::Always;
     base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-m64"]);
-    base.link_env_remove.to_mut().extend(super::apple_base::macos_link_env_remove());
+    base.link_env_remove.to_mut().extend(macos_link_env_remove());
     base.stack_probes = StackProbeType::X86;
     base.supported_sanitizers =
         SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK | SanitizerSet::THREAD;
 
-    // Clang automatically chooses a more specific target based on
-    // MACOSX_DEPLOYMENT_TARGET.  To enable cross-language LTO to work
-    // correctly, we do too.
-    let llvm_target = super::apple_base::macos_llvm_target(&arch);
-
     Target {
-        llvm_target: llvm_target.into(),
+        // Clang automatically chooses a more specific target based on
+        // MACOSX_DEPLOYMENT_TARGET.  To enable cross-language LTO to work
+        // correctly, we do too.
+        llvm_target: macos_llvm_target(arch).into(),
         pointer_width: 64,
         data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .into(),
-        arch: arch.into(),
+        arch: arch.target_arch(),
         options: TargetOptions { mcount: "\u{1}mcount".into(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_ios.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs
index db23f01c233..fbd3ebd4d04 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs
@@ -1,20 +1,18 @@
-use super::apple_sdk_base::{opts, Arch};
+use super::apple_base::{ios_sim_llvm_target, opts, Arch};
 use crate::spec::{StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts("ios", Arch::X86_64_sim);
-    let llvm_target = super::apple_base::ios_sim_llvm_target("x86_64");
-
+    let arch = Arch::X86_64_sim;
     Target {
-        llvm_target: llvm_target.into(),
+        llvm_target: ios_sim_llvm_target(arch).into(),
         pointer_width: 64,
         data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .into(),
-        arch: "x86_64".into(),
+        arch: arch.target_arch(),
         options: TargetOptions {
             max_atomic_width: Some(64),
             stack_probes: StackProbeType::X86,
-            ..base
+            ..opts("ios", arch)
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
index 13259205ac0..0f3f8519963 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
@@ -1,10 +1,11 @@
-use super::apple_sdk_base::{opts, Arch};
+use super::apple_base::{opts, Arch};
 use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
     let llvm_target = "x86_64-apple-ios13.0-macabi";
 
-    let mut base = opts("ios", Arch::X86_64_macabi);
+    let arch = Arch::X86_64_macabi;
+    let mut base = opts("ios", arch);
     base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-target", llvm_target]);
 
     Target {
@@ -12,7 +13,7 @@ pub fn target() -> Target {
         pointer_width: 64,
         data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .into(),
-        arch: "x86_64".into(),
+        arch: arch.target_arch(),
         options: TargetOptions {
             max_atomic_width: Some(64),
             stack_probes: StackProbeType::X86,
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs
index c1fd8e1c8b9..550ce0b9ce5 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs
@@ -1,17 +1,17 @@
-use super::apple_sdk_base::{opts, Arch};
+use super::apple_base::{opts, Arch};
 use crate::spec::{StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts("tvos", Arch::X86_64_sim);
+    let arch = Arch::X86_64_sim;
     Target {
         llvm_target: "x86_64-apple-tvos".into(),
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-f80:128-n8:16:32:64-S128".into(),
-        arch: "x86_64".into(),
+        arch: arch.target_arch(),
         options: TargetOptions {
             max_atomic_width: Some(64),
             stack_probes: StackProbeType::X86,
-            ..base
+            ..opts("tvos", arch)
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_watchos_sim.rs b/compiler/rustc_target/src/spec/x86_64_apple_watchos_sim.rs
index 550566b2aa7..75ce02cba1d 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_watchos_sim.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_watchos_sim.rs
@@ -1,18 +1,14 @@
-use super::apple_sdk_base::{opts, Arch};
+use super::apple_base::{opts, watchos_sim_llvm_target, Arch};
 use crate::spec::{StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts("watchos", Arch::X86_64_sim);
-
-    let arch = "x86_64";
-    let llvm_target = super::apple_base::watchos_sim_llvm_target(arch);
-
+    let arch = Arch::X86_64_sim;
     Target {
-        llvm_target: llvm_target.into(),
+        llvm_target: watchos_sim_llvm_target(arch).into(),
         pointer_width: 64,
         data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .into(),
-        arch: "x86_64".into(),
+        arch: arch.target_arch(),
         options: TargetOptions {
             max_atomic_width: Some(64),
             stack_probes: StackProbeType::X86,
@@ -28,7 +24,7 @@ pub fn target() -> Target {
                 darwinpcs\0\
                 -Os\0"
                 .into(),
-            ..base
+            ..opts("watchos", arch)
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_none_linuxkernel.rs b/compiler/rustc_target/src/spec/x86_64_unknown_none_linuxkernel.rs
deleted file mode 100644
index ebd9636ff51..00000000000
--- a/compiler/rustc_target/src/spec/x86_64_unknown_none_linuxkernel.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-// This defines the amd64 target for the Linux Kernel. See the linux-kernel-base module for
-// generic Linux kernel options.
-
-use crate::spec::{Cc, CodeModel, LinkerFlavor, Lld, Target};
-
-pub fn target() -> Target {
-    let mut base = super::linux_kernel_base::opts();
-    base.cpu = "x86-64".into();
-    base.max_atomic_width = Some(64);
-    base.features =
-        "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float".into();
-    base.code_model = Some(CodeModel::Kernel);
-    base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
-
-    Target {
-        // FIXME: Some dispute, the linux-on-clang folks think this should use
-        // "Linux". We disagree because running *on* Linux is nothing like
-        // running *as" linux, and historically the "os" component as has always
-        // been used to mean the "on" part.
-        llvm_target: "x86_64-unknown-none-elf".into(),
-        pointer_width: 64,
-        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
-            .into(),
-        arch: "x86_64".into(),
-
-        options: base,
-    }
-}
diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs
index 61cfeec4bbb..46ee2f35976 100644
--- a/compiler/rustc_trait_selection/src/autoderef.rs
+++ b/compiler/rustc_trait_selection/src/autoderef.rs
@@ -27,7 +27,6 @@ pub struct Autoderef<'a, 'tcx> {
     // Meta infos:
     infcx: &'a InferCtxt<'tcx>,
     span: Span,
-    overloaded_span: Span,
     body_id: hir::HirId,
     param_env: ty::ParamEnv<'tcx>,
 
@@ -99,12 +98,10 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
         body_id: hir::HirId,
         span: Span,
         base_ty: Ty<'tcx>,
-        overloaded_span: Span,
     ) -> Autoderef<'a, 'tcx> {
         Autoderef {
             infcx,
             span,
-            overloaded_span,
             body_id,
             param_env,
             state: AutoderefSnapshot {
@@ -193,10 +190,6 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
         self.span
     }
 
-    pub fn overloaded_span(&self) -> Span {
-        self.overloaded_span
-    }
-
     pub fn reached_recursion_limit(&self) -> bool {
         self.state.reached_recursion_limit
     }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 0f4aa87b43f..aece4ab7922 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -714,7 +714,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     obligation.cause.body_id,
                     span,
                     base_ty,
-                    span,
                 );
                 if let Some(steps) = autoderef.find_map(|(ty, steps)| {
                     // Re-add the `&`
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index bfbd4301230..cec603dcb10 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -59,6 +59,9 @@ use crate::marker::DiscriminantKind;
 use crate::marker::Tuple;
 use crate::mem;
 
+#[cfg(not(bootstrap))]
+pub mod mir;
+
 // These imports are used for simplifying intra-doc links
 #[allow(unused_imports)]
 #[cfg(all(target_has_atomic = "8", target_has_atomic = "32", target_has_atomic = "ptr"))]
diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs
new file mode 100644
index 00000000000..1bacdc39148
--- /dev/null
+++ b/library/core/src/intrinsics/mir.rs
@@ -0,0 +1,123 @@
+//! Rustc internal tooling for hand-writing MIR.
+//!
+//! If for some reasons you are not writing rustc tests and have found yourself considering using
+//! this feature, turn back. This is *exceptionally* unstable. There is no attempt at all to make
+//! anything work besides those things which the rustc test suite happened to need. If you make a
+//! typo you'll probably ICE. Really, this is not the solution to your problems. Consider instead
+//! supporting the [stable MIR project group](https://github.com/rust-lang/project-stable-mir).
+//!
+//! The documentation for this module describes how to use this feature. If you are interested in
+//! hacking on the implementation, most of that documentation lives at
+//! `rustc_mir_building/src/build/custom/mod.rs`.
+//!
+//! Typical usage will look like this:
+//!
+//! ```rust
+//! #![feature(core_intrinsics, custom_mir)]
+//!
+//! extern crate core;
+//! use core::intrinsics::mir::*;
+//!
+//! #[custom_mir(dialect = "built")]
+//! pub fn simple(x: i32) -> i32 {
+//!     mir!(
+//!         let temp1: i32;
+//!         let temp2: _;
+//!
+//!         {
+//!             temp1 = x;
+//!             Goto(exit)
+//!         }
+//!
+//!         exit = {
+//!             temp2 = Move(temp1);
+//!             RET = temp2;
+//!             Return()
+//!         }
+//!     )
+//! }
+//! ```
+//!
+//! Hopefully most of this is fairly self-explanatory. Expanding on some notable details:
+//!
+//!  - The `custom_mir` attribute tells the compiler to treat the function as being custom MIR. This
+//!    attribute only works on functions - there is no way to insert custom MIR into the middle of
+//!    another function.
+//!  - The `dialect` and `phase` parameters indicate which version of MIR you are inserting here.
+//!    This will normally be the phase that corresponds to the thing you are trying to test. The
+//!    phase can be omitted for dialects that have just one.
+//!  - You should define your function signature like you normally would. Externally, this function
+//!    can be called like any other function.
+//!  - Type inference works - you don't have to spell out the type of all of your locals.
+//!
+//! For now, all statements and terminators are parsed from nested invocations of the special
+//! functions provided in this module. We additionally want to (but do not yet) support more
+//! "normal" Rust syntax in places where it makes sense. Also, most kinds of instructions are not
+//! supported yet.
+//!
+
+#![unstable(
+    feature = "custom_mir",
+    reason = "MIR is an implementation detail and extremely unstable",
+    issue = "none"
+)]
+#![allow(unused_variables, non_snake_case, missing_debug_implementations)]
+
+/// Type representing basic blocks.
+///
+/// All terminators will have this type as a return type. It helps achieve some type safety.
+pub struct BasicBlock;
+
+macro_rules! define {
+    ($name:literal, $($sig:tt)*) => {
+        #[rustc_diagnostic_item = $name]
+        pub $($sig)* { panic!() }
+    }
+}
+
+define!("mir_return", fn Return() -> BasicBlock);
+define!("mir_goto", fn Goto(destination: BasicBlock) -> BasicBlock);
+define!("mir_retag", fn Retag<T>(place: T));
+define!("mir_retag_raw", fn RetagRaw<T>(place: T));
+define!("mir_move", fn Move<T>(place: T) -> T);
+
+/// Convenience macro for generating custom MIR.
+///
+/// See the module documentation for syntax details. This macro is not magic - it only transforms
+/// your MIR into something that is easier to parse in the compiler.
+#[rustc_macro_transparency = "transparent"]
+pub macro mir {
+    (
+        $(let $local_decl:ident $(: $local_decl_ty:ty)? ;)*
+
+        $entry_block:block
+
+        $(
+            $block_name:ident = $block:block
+        )*
+    ) => {{
+        // First, we declare all basic blocks.
+        $(
+            let $block_name: ::core::intrinsics::mir::BasicBlock;
+        )*
+
+        {
+            // Now all locals
+            #[allow(non_snake_case)]
+            let RET;
+            $(
+                let $local_decl $(: $local_decl_ty)? ;
+            )*
+
+            {
+                // Finally, the contents of the basic blocks
+                $entry_block;
+                $(
+                    $block;
+                )*
+
+                RET
+            }
+        }
+    }}
+}
diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs
index ccef35b4532..f0258640e2a 100644
--- a/library/core/src/pin.rs
+++ b/library/core/src/pin.rs
@@ -1059,7 +1059,7 @@ impl<P, U> DispatchFromDyn<Pin<U>> for Pin<P> where P: DispatchFromDyn<U> {}
 /// 8  | let x: Pin<&mut Foo> = {
 ///    |     - borrow later stored here
 /// 9  |     let x: Pin<&mut Foo> = pin!(Foo { /* … */ });
-///    |                            ^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+///    |                            ^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
 /// 10 |     x
 /// 11 | }; // <- Foo is dropped
 ///    | - temporary value is freed at the end of this statement
diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs
index 46fe50cb945..32c0ef3e116 100644
--- a/library/unwind/src/lib.rs
+++ b/library/unwind/src/lib.rs
@@ -15,7 +15,6 @@ cfg_if::cfg_if! {
         target_os = "espidf",
     ))] {
         // These "unix" family members do not have unwinder.
-        // Note this also matches x86_64-unknown-none-linuxkernel.
     } else if #[cfg(any(
         unix,
         windows,
diff --git a/src/doc/book b/src/doc/book
-Subproject aa5ee485bd6bd80d205da7c82fcdd776f92fdd5
+Subproject 3f64052c048c6def93b94a2b514ee88bba91874
diff --git a/src/doc/nomicon b/src/doc/nomicon
-Subproject 9c73283775466d22208a0b28afcab44db4c0cc1
+Subproject 05532356e7a4dbea2330aabb77611f5179493bb
diff --git a/src/doc/reference b/src/doc/reference
-Subproject 4ea7c5def38ac81df33a9e48e5637a82a5ac404
+Subproject 9f0cc13ffcd27c1fbe1ab766a9491e15ddcf4d1
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 03491f33375c5a2a1661c7fa4be671fe95ce124
+Subproject 2b15c0abf2bada6e00553814336bc3e2d839909
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
-Subproject 51a37ad19a15709d0601afbac6581f5aea6a45d
+Subproject d0dc6c97a6486f68bac782fff135086eae6d77e
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 5b4e436da7d..0315f1e3725 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -310,7 +310,6 @@ target | std | host | notes
 `x86_64-unknown-haiku` | ✓ | ✓ | 64-bit Haiku
 `x86_64-unknown-hermit` | ✓ |  | HermitCore
 `x86_64-unknown-l4re-uclibc` | ? |  |
-`x86_64-unknown-none-linuxkernel` | * |  | Linux kernel modules
 [`x86_64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 64-bit OpenBSD
 `x86_64-uwp-windows-gnu` | ✓ |  |
 `x86_64-uwp-windows-msvc` | ✓ |  |
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index 9c08eac4edc..789dd398be5 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -326,7 +326,7 @@ impl Options {
             crate::usage("rustdoc");
             return Err(0);
         } else if matches.opt_present("version") {
-            rustc_driver::version("rustdoc", matches);
+            rustc_driver::version!("rustdoc", matches);
             return Err(0);
         }
 
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index 48c6abfca90..a60e7cb10fa 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -71,7 +71,7 @@ pub(crate) fn render<T: Print, S: Print>(
     let mut themes: Vec<String> = style_files.iter().map(|s| s.basename().unwrap()).collect();
     themes.sort();
 
-    let rustdoc_version = rustc_interface::util::version_str().unwrap_or("unknown version");
+    let rustdoc_version = rustc_interface::util::version_str!().unwrap_or("unknown version");
     let content = Buffer::html().to_display(t); // Note: This must happen before making the sidebar.
     let sidebar = Buffer::html().to_display(sidebar);
     PageLayout {
diff --git a/src/test/mir-opt/building/custom/references.immut_ref.built.after.mir b/src/test/mir-opt/building/custom/references.immut_ref.built.after.mir
new file mode 100644
index 00000000000..4a5ddde4081
--- /dev/null
+++ b/src/test/mir-opt/building/custom/references.immut_ref.built.after.mir
@@ -0,0 +1,14 @@
+// MIR for `immut_ref` after built
+
+fn immut_ref(_1: &i32) -> &i32 {
+    let mut _0: &i32;                    // return place in scope 0 at $DIR/references.rs:+0:30: +0:34
+    let mut _2: *const i32;              // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+    bb0: {
+        _2 = &raw const (*_1);           // scope 0 at $DIR/references.rs:+0:1: +0:34
+        Retag([raw] _2);                 // scope 0 at $DIR/references.rs:+0:1: +0:34
+        _0 = &(*_2);                     // scope 0 at $DIR/references.rs:+0:1: +0:34
+        Retag(_0);                       // scope 0 at $DIR/references.rs:+0:1: +0:34
+        return;                          // scope 0 at $DIR/references.rs:+0:1: +0:34
+    }
+}
diff --git a/src/test/mir-opt/building/custom/references.mut_ref.built.after.mir b/src/test/mir-opt/building/custom/references.mut_ref.built.after.mir
new file mode 100644
index 00000000000..ec8509f69d1
--- /dev/null
+++ b/src/test/mir-opt/building/custom/references.mut_ref.built.after.mir
@@ -0,0 +1,14 @@
+// MIR for `mut_ref` after built
+
+fn mut_ref(_1: &mut i32) -> &mut i32 {
+    let mut _0: &mut i32;                // return place in scope 0 at $DIR/references.rs:+0:32: +0:40
+    let mut _2: *mut i32;                // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+    bb0: {
+        _2 = &raw mut (*_1);             // scope 0 at $DIR/references.rs:+0:1: +0:40
+        Retag([raw] _2);                 // scope 0 at $DIR/references.rs:+0:1: +0:40
+        _0 = &mut (*_2);                 // scope 0 at $DIR/references.rs:+0:1: +0:40
+        Retag(_0);                       // scope 0 at $DIR/references.rs:+0:1: +0:40
+        return;                          // scope 0 at $DIR/references.rs:+0:1: +0:40
+    }
+}
diff --git a/src/test/mir-opt/building/custom/references.rs b/src/test/mir-opt/building/custom/references.rs
new file mode 100644
index 00000000000..dee85722e86
--- /dev/null
+++ b/src/test/mir-opt/building/custom/references.rs
@@ -0,0 +1,43 @@
+#![feature(custom_mir, core_intrinsics)]
+
+extern crate core;
+use core::intrinsics::mir::*;
+use core::ptr::{addr_of, addr_of_mut};
+
+// EMIT_MIR references.mut_ref.built.after.mir
+#[custom_mir(dialect = "runtime", phase = "optimized")]
+pub fn mut_ref(x: &mut i32) -> &mut i32 {
+    mir!(
+        let t: *mut i32;
+
+        {
+            t = addr_of_mut!(*x);
+            RetagRaw(t);
+            RET = &mut *t;
+            Retag(RET);
+            Return()
+        }
+    )
+}
+
+// EMIT_MIR references.immut_ref.built.after.mir
+#[custom_mir(dialect = "runtime", phase = "optimized")]
+pub fn immut_ref(x: &i32) -> &i32 {
+    mir!(
+        let t: *const i32;
+
+        {
+            t = addr_of!(*x);
+            RetagRaw(t);
+            RET = & *t;
+            Retag(RET);
+            Return()
+        }
+    )
+}
+
+fn main() {
+    let mut x = 5;
+    assert_eq!(*mut_ref(&mut x), 5);
+    assert_eq!(*immut_ref(&x), 5);
+}
diff --git a/src/test/mir-opt/building/custom/simple_assign.rs b/src/test/mir-opt/building/custom/simple_assign.rs
new file mode 100644
index 00000000000..ec6dbe1d052
--- /dev/null
+++ b/src/test/mir-opt/building/custom/simple_assign.rs
@@ -0,0 +1,37 @@
+#![feature(custom_mir, core_intrinsics)]
+
+extern crate core;
+use core::intrinsics::mir::*;
+
+// EMIT_MIR simple_assign.simple.built.after.mir
+#[custom_mir(dialect = "built")]
+pub fn simple(x: i32) -> i32 {
+    mir!(
+        let temp1: i32;
+        let temp2: _;
+
+        {
+            temp1 = x;
+            Goto(exit)
+        }
+
+        exit = {
+            temp2 = Move(temp1);
+            RET = temp2;
+            Return()
+        }
+    )
+}
+
+// EMIT_MIR simple_assign.simple_ref.built.after.mir
+#[custom_mir(dialect = "built")]
+pub fn simple_ref(x: &mut i32) -> &mut i32 {
+    mir!({
+        RET = Move(x);
+        Return()
+    })
+}
+
+fn main() {
+    assert_eq!(5, simple(5));
+}
diff --git a/src/test/mir-opt/building/custom/simple_assign.simple.built.after.mir b/src/test/mir-opt/building/custom/simple_assign.simple.built.after.mir
new file mode 100644
index 00000000000..a5a2834c2e1
--- /dev/null
+++ b/src/test/mir-opt/building/custom/simple_assign.simple.built.after.mir
@@ -0,0 +1,18 @@
+// MIR for `simple` after built
+
+fn simple(_1: i32) -> i32 {
+    let mut _0: i32;                     // return place in scope 0 at $DIR/simple_assign.rs:+0:26: +0:29
+    let mut _2: i32;                     // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+    let mut _3: i32;                     // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+    bb0: {
+        _2 = _1;                         // scope 0 at $DIR/simple_assign.rs:+0:1: +0:29
+        goto -> bb1;                     // scope 0 at $DIR/simple_assign.rs:+0:1: +0:29
+    }
+
+    bb1: {
+        _3 = move _2;                    // scope 0 at $DIR/simple_assign.rs:+0:1: +0:29
+        _0 = _3;                         // scope 0 at $DIR/simple_assign.rs:+0:1: +0:29
+        return;                          // scope 0 at $DIR/simple_assign.rs:+0:1: +0:29
+    }
+}
diff --git a/src/test/mir-opt/building/custom/simple_assign.simple_ref.built.after.mir b/src/test/mir-opt/building/custom/simple_assign.simple_ref.built.after.mir
new file mode 100644
index 00000000000..6c90f0130a2
--- /dev/null
+++ b/src/test/mir-opt/building/custom/simple_assign.simple_ref.built.after.mir
@@ -0,0 +1,10 @@
+// MIR for `simple_ref` after built
+
+fn simple_ref(_1: &mut i32) -> &mut i32 {
+    let mut _0: &mut i32;                // return place in scope 0 at $DIR/simple_assign.rs:+0:35: +0:43
+
+    bb0: {
+        _0 = move _1;                    // scope 0 at $DIR/simple_assign.rs:+0:1: +0:43
+        return;                          // scope 0 at $DIR/simple_assign.rs:+0:1: +0:43
+    }
+}
diff --git a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.stderr b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.stderr
index a6af129bf39..4eeec09b910 100644
--- a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.stderr
+++ b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.stderr
@@ -4,7 +4,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let x = defer(&vec!["Goodbye", "world!"]);
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
    |                    |
-   |                    creates a temporary which is freed while still in use
+   |                    creates a temporary value which is freed while still in use
 LL |     x.x[0];
    |     ------ borrow later used here
    |
diff --git a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr
index dea8ac90bec..c62d5f903c8 100644
--- a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr
+++ b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr
@@ -4,7 +4,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     buggy_map.insert(42, &*Box::new(1));
    |                            ^^^^^^^^^^^ - temporary value is freed at the end of this statement
    |                            |
-   |                            creates a temporary which is freed while still in use
+   |                            creates a temporary value which is freed while still in use
 ...
 LL |     buggy_map.insert(43, &*tmp);
    |     --------------------------- borrow later used here
diff --git a/src/test/ui/borrowck/issue-11493.stderr b/src/test/ui/borrowck/issue-11493.stderr
index a5d1f2816f1..2720b09b0fc 100644
--- a/src/test/ui/borrowck/issue-11493.stderr
+++ b/src/test/ui/borrowck/issue-11493.stderr
@@ -4,7 +4,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let y = x.as_ref().unwrap_or(&id(5));
    |                                   ^^^^^ - temporary value is freed at the end of this statement
    |                                   |
-   |                                   creates a temporary which is freed while still in use
+   |                                   creates a temporary value which is freed while still in use
 LL |     let _ = &y;
    |             -- borrow later used here
    |
diff --git a/src/test/ui/borrowck/issue-17545.stderr b/src/test/ui/borrowck/issue-17545.stderr
index 79a1e09bd7c..3ae7e64d202 100644
--- a/src/test/ui/borrowck/issue-17545.stderr
+++ b/src/test/ui/borrowck/issue-17545.stderr
@@ -5,7 +5,7 @@ LL |   pub fn foo<'a, F: Fn(&'a ())>(bar: F) {
    |              -- lifetime `'a` defined here
 LL | /     bar.call((
 LL | |         &id(()),
-   | |          ^^^^^^ creates a temporary which is freed while still in use
+   | |          ^^^^^^ creates a temporary value which is freed while still in use
 LL | |     ));
    | |      -- temporary value is freed at the end of this statement
    | |______|
diff --git a/src/test/ui/borrowck/issue-36082.fixed b/src/test/ui/borrowck/issue-36082.fixed
index 8640ca7a509..8fc963a8566 100644
--- a/src/test/ui/borrowck/issue-36082.fixed
+++ b/src/test/ui/borrowck/issue-36082.fixed
@@ -10,7 +10,7 @@ fn main() {
     let val: &_ = binding.0;
     //~^ ERROR temporary value dropped while borrowed [E0716]
     //~| NOTE temporary value is freed at the end of this statement
-    //~| NOTE creates a temporary which is freed while still in use
+    //~| NOTE creates a temporary value which is freed while still in use
     //~| HELP consider using a `let` binding to create a longer lived value
     println!("{}", val);
     //~^ borrow later used here
diff --git a/src/test/ui/borrowck/issue-36082.rs b/src/test/ui/borrowck/issue-36082.rs
index 877d372fb84..20f66b4d45d 100644
--- a/src/test/ui/borrowck/issue-36082.rs
+++ b/src/test/ui/borrowck/issue-36082.rs
@@ -9,7 +9,7 @@ fn main() {
     let val: &_ = x.borrow().0;
     //~^ ERROR temporary value dropped while borrowed [E0716]
     //~| NOTE temporary value is freed at the end of this statement
-    //~| NOTE creates a temporary which is freed while still in use
+    //~| NOTE creates a temporary value which is freed while still in use
     //~| HELP consider using a `let` binding to create a longer lived value
     println!("{}", val);
     //~^ borrow later used here
diff --git a/src/test/ui/borrowck/issue-36082.stderr b/src/test/ui/borrowck/issue-36082.stderr
index 4bd586db1cd..a6357f8182f 100644
--- a/src/test/ui/borrowck/issue-36082.stderr
+++ b/src/test/ui/borrowck/issue-36082.stderr
@@ -4,7 +4,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let val: &_ = x.borrow().0;
    |                   ^^^^^^^^^^  - temporary value is freed at the end of this statement
    |                   |
-   |                   creates a temporary which is freed while still in use
+   |                   creates a temporary value which is freed while still in use
 ...
 LL |     println!("{}", val);
    |                    --- borrow later used here
diff --git a/src/test/ui/cleanup-rvalue-scopes-cf.stderr b/src/test/ui/cleanup-rvalue-scopes-cf.stderr
index 40f14c38984..425cd75141c 100644
--- a/src/test/ui/cleanup-rvalue-scopes-cf.stderr
+++ b/src/test/ui/cleanup-rvalue-scopes-cf.stderr
@@ -4,7 +4,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let x1 = arg(&AddFlags(1));
    |                   ^^^^^^^^^^^ - temporary value is freed at the end of this statement
    |                   |
-   |                   creates a temporary which is freed while still in use
+   |                   creates a temporary value which is freed while still in use
 ...
 LL |     (x1, x2, x3, x4, x5, x6, x7);
    |      -- borrow later used here
@@ -21,7 +21,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let x2 = AddFlags(1).get();
    |              ^^^^^^^^^^^      - temporary value is freed at the end of this statement
    |              |
-   |              creates a temporary which is freed while still in use
+   |              creates a temporary value which is freed while still in use
 ...
 LL |     (x1, x2, x3, x4, x5, x6, x7);
    |          -- borrow later used here
@@ -38,7 +38,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let x3 = &*arg(&AddFlags(1));
    |                     ^^^^^^^^^^^ - temporary value is freed at the end of this statement
    |                     |
-   |                     creates a temporary which is freed while still in use
+   |                     creates a temporary value which is freed while still in use
 ...
 LL |     (x1, x2, x3, x4, x5, x6, x7);
    |              -- borrow later used here
@@ -55,7 +55,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let ref x4 = *arg(&AddFlags(1));
    |                        ^^^^^^^^^^^ - temporary value is freed at the end of this statement
    |                        |
-   |                        creates a temporary which is freed while still in use
+   |                        creates a temporary value which is freed while still in use
 ...
 LL |     (x1, x2, x3, x4, x5, x6, x7);
    |                  -- borrow later used here
@@ -72,7 +72,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let &ref x5 = arg(&AddFlags(1));
    |                        ^^^^^^^^^^^ - temporary value is freed at the end of this statement
    |                        |
-   |                        creates a temporary which is freed while still in use
+   |                        creates a temporary value which is freed while still in use
 ...
 LL |     (x1, x2, x3, x4, x5, x6, x7);
    |                      -- borrow later used here
@@ -89,7 +89,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let x6 = AddFlags(1).get();
    |              ^^^^^^^^^^^      - temporary value is freed at the end of this statement
    |              |
-   |              creates a temporary which is freed while still in use
+   |              creates a temporary value which is freed while still in use
 ...
 LL |     (x1, x2, x3, x4, x5, x6, x7);
    |                          -- borrow later used here
@@ -106,7 +106,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let StackBox { f: x7 } = StackBox { f: AddFlags(1).get() };
    |                                            ^^^^^^^^^^^        - temporary value is freed at the end of this statement
    |                                            |
-   |                                            creates a temporary which is freed while still in use
+   |                                            creates a temporary value which is freed while still in use
 LL |
 LL |     (x1, x2, x3, x4, x5, x6, x7);
    |                              -- borrow later used here
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
index 78143042ece..ed6a6ee6e0f 100644
--- a/src/test/ui/consts/const-eval/const-eval-intrinsic-promotion.stderr
+++ b/src/test/ui/consts/const-eval/const-eval-intrinsic-promotion.stderr
@@ -4,7 +4,7 @@ error[E0716]: temporary value dropped while borrowed
 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
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
 LL | }
    | - temporary value is freed at the end of this statement
 
diff --git a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr
index 69e3ca716a9..2e697b219c5 100644
--- a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr
+++ b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr
@@ -10,7 +10,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/dont_promote_unstable_const_fn.rs:17:28
    |
 LL |     let _: &'static u32 = &foo();
-   |            ------------    ^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL | }
@@ -20,7 +20,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/dont_promote_unstable_const_fn.rs:21:28
    |
 LL |     let _: &'static u32 = &meh();
-   |            ------------    ^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -31,7 +31,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/dont_promote_unstable_const_fn.rs:22:26
    |
 LL |     let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis();
-   |            ----------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ----------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL |
diff --git a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.stderr b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.stderr
index 129f0615107..aa742d784e0 100644
--- a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.stderr
+++ b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.stderr
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/dont_promote_unstable_const_fn_cross_crate.rs:8:28
    |
 LL |     let _: &'static u32 = &foo();
-   |            ------------    ^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL |     let _x: &'static u32 = &foo();
@@ -13,7 +13,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/dont_promote_unstable_const_fn_cross_crate.rs:9:29
    |
 LL |     let _x: &'static u32 = &foo();
-   |             ------------    ^^^^^ creates a temporary which is freed while still in use
+   |             ------------    ^^^^^ creates a temporary value which is freed while still in use
    |             |
    |             type annotation requires that borrow lasts for `'static`
 LL | }
diff --git a/src/test/ui/consts/const-eval/promoted_const_fn_fail.stderr b/src/test/ui/consts/const-eval/promoted_const_fn_fail.stderr
index 596fa090d97..2d4e7c83d3e 100644
--- a/src/test/ui/consts/const-eval/promoted_const_fn_fail.stderr
+++ b/src/test/ui/consts/const-eval/promoted_const_fn_fail.stderr
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promoted_const_fn_fail.rs:17:27
    |
 LL |     let x: &'static u8 = &(bar() + 1);
-   |            -----------    ^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            -----------    ^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
diff --git a/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.stderr b/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.stderr
index 63dc43a41a8..9ebae3a18a3 100644
--- a/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.stderr
+++ b/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.stderr
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promoted_const_fn_fail_deny_const_err.rs:18:27
    |
 LL |     let x: &'static u8 = &(bar() + 1);
-   |            -----------    ^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            -----------    ^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
diff --git a/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.stderr b/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.stderr
index 8ac60da3863..01fcf2ec213 100644
--- a/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.stderr
+++ b/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.stderr
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promoted_raw_ptr_ops.rs:2:29
    |
 LL |     let x: &'static bool = &(42 as *const i32 == 43 as *const i32);
-   |            -------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            -------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -13,7 +13,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promoted_raw_ptr_ops.rs:4:30
    |
 LL |     let y: &'static usize = &(&1 as *const i32 as usize + 1);
-   |            --------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            --------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -24,7 +24,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promoted_raw_ptr_ops.rs:6:28
    |
 LL |     let z: &'static i32 = &(unsafe { *(42 as *const i32) });
-   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -35,7 +35,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promoted_raw_ptr_ops.rs:8:29
    |
 LL |     let a: &'static bool = &(main as fn() == main as fn());
-   |            -------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            -------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL |
diff --git a/src/test/ui/consts/const-eval/transmute-const-promotion.stderr b/src/test/ui/consts/const-eval/transmute-const-promotion.stderr
index 15b9b56ea66..434a957f648 100644
--- a/src/test/ui/consts/const-eval/transmute-const-promotion.stderr
+++ b/src/test/ui/consts/const-eval/transmute-const-promotion.stderr
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/transmute-const-promotion.rs:4:37
    |
 LL |     let x: &'static u32 = unsafe { &mem::transmute(3.0f32) };
-   |            ------------             ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ------------             ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL |
diff --git a/src/test/ui/consts/const-eval/union_promotion.stderr b/src/test/ui/consts/const-eval/union_promotion.stderr
index 70808c520d3..42f17de2003 100644
--- a/src/test/ui/consts/const-eval/union_promotion.stderr
+++ b/src/test/ui/consts/const-eval/union_promotion.stderr
@@ -7,7 +7,7 @@ LL |       let x: &'static bool = &unsafe {
    | |            type annotation requires that borrow lasts for `'static`
 LL | |         Foo { a: &1 }.b == Foo { a: &2 }.b
 LL | |     };
-   | |_____^ creates a temporary which is freed while still in use
+   | |_____^ creates a temporary value which is freed while still in use
 LL |   }
    |   - temporary value is freed at the end of this statement
 
diff --git a/src/test/ui/consts/const-int-conversion.stderr b/src/test/ui/consts/const-int-conversion.stderr
index 61162a79226..5dd757e3f5e 100644
--- a/src/test/ui/consts/const-int-conversion.stderr
+++ b/src/test/ui/consts/const-int-conversion.stderr
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-conversion.rs:2:28
    |
 LL |     let x: &'static i32 = &(5_i32.reverse_bits());
-   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -13,7 +13,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-conversion.rs:4:28
    |
 LL |     let y: &'static i32 = &(i32::from_be_bytes([0x12, 0x34, 0x56, 0x78]));
-   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -24,7 +24,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-conversion.rs:6:28
    |
 LL |     let z: &'static i32 = &(i32::from_le_bytes([0x12, 0x34, 0x56, 0x78]));
-   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -35,7 +35,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-conversion.rs:8:28
    |
 LL |     let a: &'static i32 = &(i32::from_be(i32::from_ne_bytes([0x80, 0, 0, 0])));
-   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -46,7 +46,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-conversion.rs:10:29
    |
 LL |     let b: &'static [u8] = &(0x12_34_56_78_i32.to_be_bytes());
-   |            -------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            -------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -57,7 +57,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-conversion.rs:12:29
    |
 LL |     let c: &'static [u8] = &(0x12_34_56_78_i32.to_le_bytes());
-   |            -------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            -------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -68,7 +68,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-conversion.rs:14:29
    |
 LL |     let d: &'static [u8] = &(i32::MIN.to_be().to_ne_bytes());
-   |            -------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            -------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL |
diff --git a/src/test/ui/consts/const-int-overflowing.stderr b/src/test/ui/consts/const-int-overflowing.stderr
index 56c7f7f092d..7d3689e6ec7 100644
--- a/src/test/ui/consts/const-int-overflowing.stderr
+++ b/src/test/ui/consts/const-int-overflowing.stderr
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-overflowing.rs:2:36
    |
 LL |     let x: &'static (i32, bool) = &(5_i32.overflowing_add(3));
-   |            --------------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            --------------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -13,7 +13,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-overflowing.rs:4:36
    |
 LL |     let y: &'static (i32, bool) = &(5_i32.overflowing_sub(3));
-   |            --------------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            --------------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -24,7 +24,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-overflowing.rs:6:36
    |
 LL |     let z: &'static (i32, bool) = &(5_i32.overflowing_mul(3));
-   |            --------------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            --------------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL |
diff --git a/src/test/ui/consts/const-int-rotate.stderr b/src/test/ui/consts/const-int-rotate.stderr
index ed265804bbc..039da1c31c5 100644
--- a/src/test/ui/consts/const-int-rotate.stderr
+++ b/src/test/ui/consts/const-int-rotate.stderr
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-rotate.rs:2:28
    |
 LL |     let x: &'static i32 = &(5_i32.rotate_left(3));
-   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -13,7 +13,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-rotate.rs:4:28
    |
 LL |     let y: &'static i32 = &(5_i32.rotate_right(3));
-   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL |
diff --git a/src/test/ui/consts/const-int-sign.stderr b/src/test/ui/consts/const-int-sign.stderr
index 5f8fd414180..fc23d9d2b29 100644
--- a/src/test/ui/consts/const-int-sign.stderr
+++ b/src/test/ui/consts/const-int-sign.stderr
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-sign.rs:2:29
    |
 LL |     let x: &'static bool = &(5_i32.is_negative());
-   |            -------------    ^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            -------------    ^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -13,7 +13,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-sign.rs:4:29
    |
 LL |     let y: &'static bool = &(5_i32.is_positive());
-   |            -------------    ^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            -------------    ^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL |
diff --git a/src/test/ui/consts/const-int-wrapping.stderr b/src/test/ui/consts/const-int-wrapping.stderr
index 5174b72659c..1342fadc405 100644
--- a/src/test/ui/consts/const-int-wrapping.stderr
+++ b/src/test/ui/consts/const-int-wrapping.stderr
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-wrapping.rs:2:28
    |
 LL |     let x: &'static i32 = &(5_i32.wrapping_add(3));
-   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -13,7 +13,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-wrapping.rs:4:28
    |
 LL |     let y: &'static i32 = &(5_i32.wrapping_sub(3));
-   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -24,7 +24,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-wrapping.rs:6:28
    |
 LL |     let z: &'static i32 = &(5_i32.wrapping_mul(3));
-   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -35,7 +35,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-wrapping.rs:8:28
    |
 LL |     let a: &'static i32 = &(5_i32.wrapping_shl(3));
-   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -46,7 +46,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-wrapping.rs:10:28
    |
 LL |     let b: &'static i32 = &(5_i32.wrapping_shr(3));
-   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL |
diff --git a/src/test/ui/consts/const-mut-refs/mut_ref_in_final.stderr b/src/test/ui/consts/const-mut-refs/mut_ref_in_final.stderr
index 3a9ce79f10e..78c58b5ab09 100644
--- a/src/test/ui/consts/const-mut-refs/mut_ref_in_final.stderr
+++ b/src/test/ui/consts/const-mut-refs/mut_ref_in_final.stderr
@@ -11,7 +11,7 @@ LL | const B3: Option<&mut i32> = Some(&mut 42);
    |                              ----------^^-
    |                              |         | |
    |                              |         | temporary value is freed at the end of this statement
-   |                              |         creates a temporary which is freed while still in use
+   |                              |         creates a temporary value which is freed while still in use
    |                              using this value as a constant requires that borrow lasts for `'static`
 
 error[E0716]: temporary value dropped while borrowed
@@ -21,7 +21,7 @@ LL | const B4: Option<&mut i32> = helper(&mut 42);
    |                              ------------^^-
    |                              |           | |
    |                              |           | temporary value is freed at the end of this statement
-   |                              |           creates a temporary which is freed while still in use
+   |                              |           creates a temporary value which is freed while still in use
    |                              using this value as a constant requires that borrow lasts for `'static`
 
 error[E0716]: temporary value dropped while borrowed
@@ -31,7 +31,7 @@ LL | const FOO: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42));
    |                                  -------------------------------^^--
    |                                  |                              |  |
    |                                  |                              |  temporary value is freed at the end of this statement
-   |                                  |                              creates a temporary which is freed while still in use
+   |                                  |                              creates a temporary value which is freed while still in use
    |                                  using this value as a constant requires that borrow lasts for `'static`
 
 error[E0716]: temporary value dropped while borrowed
@@ -41,7 +41,7 @@ LL | static FOO2: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42));
    |                                    -------------------------------^^--
    |                                    |                              |  |
    |                                    |                              |  temporary value is freed at the end of this statement
-   |                                    |                              creates a temporary which is freed while still in use
+   |                                    |                              creates a temporary value which is freed while still in use
    |                                    using this value as a static requires that borrow lasts for `'static`
 
 error[E0716]: temporary value dropped while borrowed
@@ -51,7 +51,7 @@ LL | static mut FOO3: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42));
    |                                        -------------------------------^^--
    |                                        |                              |  |
    |                                        |                              |  temporary value is freed at the end of this statement
-   |                                        |                              creates a temporary which is freed while still in use
+   |                                        |                              creates a temporary value which is freed while still in use
    |                                        using this value as a static requires that borrow lasts for `'static`
 
 error: aborting due to 6 previous errors
diff --git a/src/test/ui/consts/const-ptr-nonnull.stderr b/src/test/ui/consts/const-ptr-nonnull.stderr
index 26946fb9902..dbcb0c86052 100644
--- a/src/test/ui/consts/const-ptr-nonnull.stderr
+++ b/src/test/ui/consts/const-ptr-nonnull.stderr
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-ptr-nonnull.rs:4:37
    |
 LL |     let x: &'static NonNull<u32> = &(NonNull::dangling());
-   |            ---------------------    ^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ---------------------    ^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -13,7 +13,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-ptr-nonnull.rs:9:37
    |
 LL |     let x: &'static NonNull<u32> = &(non_null.cast());
-   |            ---------------------    ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ---------------------    ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL |
diff --git a/src/test/ui/consts/const-ptr-unique.stderr b/src/test/ui/consts/const-ptr-unique.stderr
index 3644cf4cec7..83448c3e8d8 100644
--- a/src/test/ui/consts/const-ptr-unique.stderr
+++ b/src/test/ui/consts/const-ptr-unique.stderr
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-ptr-unique.rs:8:33
    |
 LL |     let x: &'static *mut u32 = &(unique.as_ptr());
-   |            -----------------    ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            -----------------    ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL |
diff --git a/src/test/ui/consts/control-flow/interior-mutability.stderr b/src/test/ui/consts/control-flow/interior-mutability.stderr
index 4f9c7d34c35..db2ffb91b98 100644
--- a/src/test/ui/consts/control-flow/interior-mutability.stderr
+++ b/src/test/ui/consts/control-flow/interior-mutability.stderr
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/interior-mutability.rs:40:26
    |
 LL |     let x: &'static _ = &X;
-   |            ----------    ^ creates a temporary which is freed while still in use
+   |            ----------    ^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -13,7 +13,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/interior-mutability.rs:41:26
    |
 LL |     let y: &'static _ = &Y;
-   |            ----------    ^ creates a temporary which is freed while still in use
+   |            ----------    ^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL |     let z: &'static _ = &Z;
@@ -24,7 +24,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/interior-mutability.rs:42:26
    |
 LL |     let z: &'static _ = &Z;
-   |            ----------    ^ creates a temporary which is freed while still in use
+   |            ----------    ^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL | }
diff --git a/src/test/ui/consts/issue-54224.stderr b/src/test/ui/consts/issue-54224.stderr
index 8dcb4daca3b..55fe55759df 100644
--- a/src/test/ui/consts/issue-54224.stderr
+++ b/src/test/ui/consts/issue-54224.stderr
@@ -5,7 +5,7 @@ LL | const FOO: Option<&[[u8; 3]]> = Some(&[*b"foo"]);
    |                                 ------^^^^^^^^^-
    |                                 |     |        |
    |                                 |     |        temporary value is freed at the end of this statement
-   |                                 |     creates a temporary which is freed while still in use
+   |                                 |     creates a temporary value which is freed while still in use
    |                                 using this value as a constant requires that borrow lasts for `'static`
 
 error[E0716]: temporary value dropped while borrowed
@@ -15,7 +15,7 @@ LL | pub const Z: Cow<'static, [ [u8; 3] ]> = Cow::Borrowed(&[*b"ABC"]);
    |                                          ---------------^^^^^^^^^-
    |                                          |              |        |
    |                                          |              |        temporary value is freed at the end of this statement
-   |                                          |              creates a temporary which is freed while still in use
+   |                                          |              creates a temporary value which is freed while still in use
    |                                          using this value as a constant requires that borrow lasts for `'static`
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/consts/min_const_fn/promotion.stderr b/src/test/ui/consts/min_const_fn/promotion.stderr
index 550423c2d93..0b8dc0ce0e9 100644
--- a/src/test/ui/consts/min_const_fn/promotion.stderr
+++ b/src/test/ui/consts/min_const_fn/promotion.stderr
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promotion.rs:11:27
    |
 LL |     let x: &'static () = &foo1();
-   |            -----------    ^^^^^^ creates a temporary which is freed while still in use
+   |            -----------    ^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -13,7 +13,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promotion.rs:12:28
    |
 LL |     let y: &'static i32 = &foo2(42);
-   |            ------------    ^^^^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -24,7 +24,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promotion.rs:13:28
    |
 LL |     let z: &'static i32 = &foo3();
-   |            ------------    ^^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -35,7 +35,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promotion.rs:14:34
    |
 LL |     let a: &'static Cell<i32> = &foo4();
-   |            ------------------    ^^^^^^ creates a temporary which is freed while still in use
+   |            ------------------    ^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -46,7 +46,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promotion.rs:15:42
    |
 LL |     let a: &'static Option<Cell<i32>> = &foo5();
-   |            --------------------------    ^^^^^^ creates a temporary which is freed while still in use
+   |            --------------------------    ^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL |     let a: &'static Option<Cell<i32>> = &foo6();
@@ -57,7 +57,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promotion.rs:16:42
    |
 LL |     let a: &'static Option<Cell<i32>> = &foo6();
-   |            --------------------------    ^^^^^^ creates a temporary which is freed while still in use
+   |            --------------------------    ^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL | }
diff --git a/src/test/ui/consts/promote-not.stderr b/src/test/ui/consts/promote-not.stderr
index 0d0b0f9c689..b93358e8dcc 100644
--- a/src/test/ui/consts/promote-not.stderr
+++ b/src/test/ui/consts/promote-not.stderr
@@ -5,14 +5,14 @@ LL | static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]);
    |                                        ----------^^^^^^^^^-
    |                                        |         |        |
    |                                        |         |        temporary value is freed at the end of this statement
-   |                                        |         creates a temporary which is freed while still in use
+   |                                        |         creates a temporary value which is freed while still in use
    |                                        using this value as a static requires that borrow lasts for `'static`
 
 error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:11:18
    |
 LL |     let x = &mut [1,2,3];
-   |                  ^^^^^^^ creates a temporary which is freed while still in use
+   |                  ^^^^^^^ creates a temporary value which is freed while still in use
 LL |     x
    |     - using this value as a static requires that borrow lasts for `'static`
 LL | };
@@ -22,7 +22,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:20:32
    |
 LL |         let _x: &'static () = &foo();
-   |                 -----------    ^^^^^ creates a temporary which is freed while still in use
+   |                 -----------    ^^^^^ creates a temporary value which is freed while still in use
    |                 |
    |                 type annotation requires that borrow lasts for `'static`
 LL |     }
@@ -32,7 +32,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:28:29
    |
 LL |     let _x: &'static i32 = &unsafe { U { x: 0 }.x };
-   |             ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |             ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |             |
    |             type annotation requires that borrow lasts for `'static`
 LL | }
@@ -42,7 +42,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:33:29
    |
 LL |     let _x: &'static i32 = &unsafe { U { x: 0 }.x };
-   |             ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |             ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |             |
    |             type annotation requires that borrow lasts for `'static`
 LL | };
@@ -52,7 +52,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:39:29
    |
 LL |     let _val: &'static _ = &(Cell::new(1), 2).1;
-   |               ----------    ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |               ----------    ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
 LL | };
@@ -62,7 +62,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:46:29
    |
 LL |     let _val: &'static _ = &(Cell::new(1), 2).0;
-   |               ----------    ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |               ----------    ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
 ...
@@ -73,7 +73,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:47:29
    |
 LL |     let _val: &'static _ = &(Cell::new(1), 2).1;
-   |               ----------    ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |               ----------    ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
 ...
@@ -84,7 +84,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:50:29
    |
 LL |     let _val: &'static _ = &(1/0);
-   |               ----------    ^^^^^ creates a temporary which is freed while still in use
+   |               ----------    ^^^^^ creates a temporary value which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
 ...
@@ -95,7 +95,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:51:29
    |
 LL |     let _val: &'static _ = &(1/(1-1));
-   |               ----------    ^^^^^^^^^ creates a temporary which is freed while still in use
+   |               ----------    ^^^^^^^^^ creates a temporary value which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
 ...
@@ -106,7 +106,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:52:29
    |
 LL |     let _val: &'static _ = &(1%0);
-   |               ----------    ^^^^^ creates a temporary which is freed while still in use
+   |               ----------    ^^^^^ creates a temporary value which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
 ...
@@ -117,7 +117,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:53:29
    |
 LL |     let _val: &'static _ = &(1%(1-1));
-   |               ----------    ^^^^^^^^^ creates a temporary which is freed while still in use
+   |               ----------    ^^^^^^^^^ creates a temporary value which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
 ...
@@ -128,7 +128,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:54:29
    |
 LL |     let _val: &'static _ = &([1,2,3][4]+1);
-   |               ----------    ^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |               ----------    ^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
 ...
@@ -139,7 +139,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:57:29
    |
 LL |     let _val: &'static _ = &TEST_DROP;
-   |               ----------    ^^^^^^^^^ creates a temporary which is freed while still in use
+   |               ----------    ^^^^^^^^^ creates a temporary value which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
 ...
@@ -150,7 +150,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:59:29
    |
 LL |     let _val: &'static _ = &&TEST_DROP;
-   |               ----------    ^^^^^^^^^^ creates a temporary which is freed while still in use
+   |               ----------    ^^^^^^^^^^ creates a temporary value which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
 ...
@@ -161,7 +161,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:59:30
    |
 LL |     let _val: &'static _ = &&TEST_DROP;
-   |               ----------     ^^^^^^^^^ creates a temporary which is freed while still in use
+   |               ----------     ^^^^^^^^^ creates a temporary value which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
 ...
@@ -172,7 +172,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:62:29
    |
 LL |     let _val: &'static _ = &(&TEST_DROP,);
-   |               ----------    ^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |               ----------    ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
 ...
@@ -183,7 +183,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:62:31
    |
 LL |     let _val: &'static _ = &(&TEST_DROP,);
-   |               ----------      ^^^^^^^^^ creates a temporary which is freed while still in use
+   |               ----------      ^^^^^^^^^ creates a temporary value which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
 ...
@@ -194,7 +194,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:65:29
    |
 LL |     let _val: &'static _ = &[&TEST_DROP; 1];
-   |               ----------    ^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |               ----------    ^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
 ...
@@ -207,7 +207,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let _val: &'static _ = &[&TEST_DROP; 1];
    |               ----------      ^^^^^^^^^    - temporary value is freed at the end of this statement
    |               |               |
-   |               |               creates a temporary which is freed while still in use
+   |               |               creates a temporary value which is freed while still in use
    |               type annotation requires that borrow lasts for `'static`
 
 error: aborting due to 20 previous errors
diff --git a/src/test/ui/consts/promote_const_let.stderr b/src/test/ui/consts/promote_const_let.stderr
index c47d297c904..975a235a649 100644
--- a/src/test/ui/consts/promote_const_let.stderr
+++ b/src/test/ui/consts/promote_const_let.stderr
@@ -19,7 +19,7 @@ LL |       let x: &'static u32 = &{
 LL | |         let y = 42;
 LL | |         y
 LL | |     };
-   | |_____^ creates a temporary which is freed while still in use
+   | |_____^ creates a temporary value which is freed while still in use
 LL |   }
    |   - temporary value is freed at the end of this statement
 
diff --git a/src/test/ui/consts/promoted-const-drop.stderr b/src/test/ui/consts/promoted-const-drop.stderr
index 184ba0ea3b3..4802834173f 100644
--- a/src/test/ui/consts/promoted-const-drop.stderr
+++ b/src/test/ui/consts/promoted-const-drop.stderr
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promoted-const-drop.rs:13:26
    |
 LL |     let _: &'static A = &A();
-   |            ----------    ^^^ creates a temporary which is freed while still in use
+   |            ----------    ^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL |     let _: &'static [A] = &[C];
@@ -13,7 +13,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promoted-const-drop.rs:14:28
    |
 LL |     let _: &'static [A] = &[C];
-   |            ------------    ^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL | }
diff --git a/src/test/ui/consts/qualif-union.stderr b/src/test/ui/consts/qualif-union.stderr
index 8ec68ada048..d847cf88f50 100644
--- a/src/test/ui/consts/qualif-union.stderr
+++ b/src/test/ui/consts/qualif-union.stderr
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/qualif-union.rs:28:26
    |
 LL |     let _: &'static _ = &C1;
-   |            ----------    ^^ creates a temporary which is freed while still in use
+   |            ----------    ^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -13,7 +13,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/qualif-union.rs:29:26
    |
 LL |     let _: &'static _ = &C2;
-   |            ----------    ^^ creates a temporary which is freed while still in use
+   |            ----------    ^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -24,7 +24,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/qualif-union.rs:30:26
    |
 LL |     let _: &'static _ = &C3;
-   |            ----------    ^^ creates a temporary which is freed while still in use
+   |            ----------    ^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -35,7 +35,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/qualif-union.rs:31:26
    |
 LL |     let _: &'static _ = &C4;
-   |            ----------    ^^ creates a temporary which is freed while still in use
+   |            ----------    ^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL |     let _: &'static _ = &C5;
@@ -46,7 +46,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/qualif-union.rs:32:26
    |
 LL |     let _: &'static _ = &C5;
-   |            ----------    ^^ creates a temporary which is freed while still in use
+   |            ----------    ^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL | }
diff --git a/src/test/ui/feature-gates/feature-gate-abi-efiapi.rs b/src/test/ui/feature-gates/feature-gate-abi-efiapi.rs
new file mode 100644
index 00000000000..0c0d736acd0
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-abi-efiapi.rs
@@ -0,0 +1,33 @@
+// needs-llvm-components: x86
+// compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib
+#![no_core]
+#![feature(no_core, lang_items)]
+#[lang="sized"]
+trait Sized { }
+
+// Functions
+extern "efiapi" fn f1() {} //~ ERROR efiapi ABI is experimental
+
+// Methods in trait defintion
+trait Tr {
+    extern "efiapi" fn f2(); //~ ERROR efiapi ABI is experimental
+    extern "efiapi" fn f3() {} //~ ERROR efiapi ABI is experimental
+}
+
+struct S;
+
+// Methods in trait impl
+impl Tr for S {
+    extern "efiapi" fn f2() {} //~ ERROR efiapi ABI is experimental
+}
+
+// Methods in inherent impl
+impl S {
+    extern "efiapi" fn f4() {} //~ ERROR efiapi ABI is experimental
+}
+
+// Function pointer types
+type A = extern "efiapi" fn(); //~ ERROR efiapi ABI is experimental
+
+// Foreign modules
+extern "efiapi" {} //~ ERROR efiapi ABI is experimental
diff --git a/src/test/ui/feature-gates/feature-gate-abi-efiapi.stderr b/src/test/ui/feature-gates/feature-gate-abi-efiapi.stderr
new file mode 100644
index 00000000000..5b01dcc6d85
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-abi-efiapi.stderr
@@ -0,0 +1,66 @@
+error[E0658]: efiapi ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi-efiapi.rs:9:8
+   |
+LL | extern "efiapi" fn f1() {}
+   |        ^^^^^^^^
+   |
+   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
+   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
+
+error[E0658]: efiapi ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi-efiapi.rs:13:12
+   |
+LL |     extern "efiapi" fn f2();
+   |            ^^^^^^^^
+   |
+   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
+   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
+
+error[E0658]: efiapi ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi-efiapi.rs:14:12
+   |
+LL |     extern "efiapi" fn f3() {}
+   |            ^^^^^^^^
+   |
+   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
+   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
+
+error[E0658]: efiapi ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi-efiapi.rs:21:12
+   |
+LL |     extern "efiapi" fn f2() {}
+   |            ^^^^^^^^
+   |
+   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
+   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
+
+error[E0658]: efiapi ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi-efiapi.rs:26:12
+   |
+LL |     extern "efiapi" fn f4() {}
+   |            ^^^^^^^^
+   |
+   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
+   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
+
+error[E0658]: efiapi ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi-efiapi.rs:30:17
+   |
+LL | type A = extern "efiapi" fn();
+   |                 ^^^^^^^^
+   |
+   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
+   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
+
+error[E0658]: efiapi ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi-efiapi.rs:33:8
+   |
+LL | extern "efiapi" {}
+   |        ^^^^^^^^
+   |
+   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
+   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-abi.rs b/src/test/ui/feature-gates/feature-gate-abi.rs
index 15b674c62e4..712655f9775 100644
--- a/src/test/ui/feature-gates/feature-gate-abi.rs
+++ b/src/test/ui/feature-gates/feature-gate-abi.rs
@@ -1,6 +1,5 @@
 // gate-test-intrinsics
 // gate-test-platform_intrinsics
-// gate-test-abi_efiapi
 // compile-flags: --crate-type=rlib
 
 #![feature(no_core, lang_items)]
@@ -18,7 +17,6 @@ extern "rust-intrinsic" fn f1() {} //~ ERROR intrinsics are subject to change
 extern "platform-intrinsic" fn f2() {} //~ ERROR platform intrinsics are experimental
                                        //~^ ERROR intrinsic must be in
 extern "rust-call" fn f4(_: ()) {} //~ ERROR rust-call ABI is subject to change
-extern "efiapi" fn f10() {} //~ ERROR efiapi ABI is experimental and subject to change
 
 // Methods in trait definition
 trait Tr {
@@ -27,10 +25,8 @@ trait Tr {
     extern "platform-intrinsic" fn m2(); //~ ERROR platform intrinsics are experimental
                                          //~^ ERROR intrinsic must be in
     extern "rust-call" fn m4(_: ()); //~ ERROR rust-call ABI is subject to change
-    extern "efiapi" fn m10(); //~ ERROR efiapi ABI is experimental and subject to change
 
     extern "rust-call" fn dm4(_: ()) {} //~ ERROR rust-call ABI is subject to change
-    extern "efiapi" fn dm10() {} //~ ERROR efiapi ABI is experimental and subject to change
 }
 
 struct S;
@@ -42,7 +38,6 @@ impl Tr for S {
     extern "platform-intrinsic" fn m2() {} //~ ERROR platform intrinsics are experimental
                                            //~^ ERROR intrinsic must be in
     extern "rust-call" fn m4(_: ()) {} //~ ERROR rust-call ABI is subject to change
-    extern "efiapi" fn m10() {} //~ ERROR efiapi ABI is experimental and subject to change
 }
 
 // Methods in inherent impl
@@ -52,17 +47,14 @@ impl S {
     extern "platform-intrinsic" fn im2() {} //~ ERROR platform intrinsics are experimental
                                             //~^ ERROR intrinsic must be in
     extern "rust-call" fn im4(_: ()) {} //~ ERROR rust-call ABI is subject to change
-    extern "efiapi" fn im10() {} //~ ERROR efiapi ABI is experimental and subject to change
 }
 
 // Function pointer types
 type A1 = extern "rust-intrinsic" fn(); //~ ERROR intrinsics are subject to change
 type A2 = extern "platform-intrinsic" fn(); //~ ERROR platform intrinsics are experimental
 type A4 = extern "rust-call" fn(_: ()); //~ ERROR rust-call ABI is subject to change
-type A10 = extern "efiapi" fn(); //~ ERROR efiapi ABI is experimental and subject to change
 
 // Foreign modules
 extern "rust-intrinsic" {} //~ ERROR intrinsics are subject to change
 extern "platform-intrinsic" {} //~ ERROR platform intrinsics are experimental
 extern "rust-call" {} //~ ERROR rust-call ABI is subject to change
-extern "efiapi" {} //~ ERROR efiapi ABI is experimental and subject to change
diff --git a/src/test/ui/feature-gates/feature-gate-abi.stderr b/src/test/ui/feature-gates/feature-gate-abi.stderr
index 33ec250f090..e9791b9513f 100644
--- a/src/test/ui/feature-gates/feature-gate-abi.stderr
+++ b/src/test/ui/feature-gates/feature-gate-abi.stderr
@@ -1,5 +1,5 @@
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:16:8
+  --> $DIR/feature-gate-abi.rs:15:8
    |
 LL | extern "rust-intrinsic" fn f1() {}
    |        ^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL | extern "rust-intrinsic" fn f1() {}
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:18:8
+  --> $DIR/feature-gate-abi.rs:17:8
    |
 LL | extern "platform-intrinsic" fn f2() {}
    |        ^^^^^^^^^^^^^^^^^^^^
@@ -16,7 +16,7 @@ LL | extern "platform-intrinsic" fn f2() {}
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:20:8
+  --> $DIR/feature-gate-abi.rs:19:8
    |
 LL | extern "rust-call" fn f4(_: ()) {}
    |        ^^^^^^^^^^^
@@ -24,17 +24,8 @@ LL | extern "rust-call" fn f4(_: ()) {}
    = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
-error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:21:8
-   |
-LL | extern "efiapi" fn f10() {}
-   |        ^^^^^^^^
-   |
-   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
-   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
-
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:25:12
+  --> $DIR/feature-gate-abi.rs:23:12
    |
 LL |     extern "rust-intrinsic" fn m1();
    |            ^^^^^^^^^^^^^^^^
@@ -42,7 +33,7 @@ LL |     extern "rust-intrinsic" fn m1();
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:27:12
+  --> $DIR/feature-gate-abi.rs:25:12
    |
 LL |     extern "platform-intrinsic" fn m2();
    |            ^^^^^^^^^^^^^^^^^^^^
@@ -51,7 +42,7 @@ LL |     extern "platform-intrinsic" fn m2();
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:29:12
+  --> $DIR/feature-gate-abi.rs:27:12
    |
 LL |     extern "rust-call" fn m4(_: ());
    |            ^^^^^^^^^^^
@@ -59,17 +50,8 @@ LL |     extern "rust-call" fn m4(_: ());
    = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
-error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:30:12
-   |
-LL |     extern "efiapi" fn m10();
-   |            ^^^^^^^^
-   |
-   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
-   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
-
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:32:12
+  --> $DIR/feature-gate-abi.rs:29:12
    |
 LL |     extern "rust-call" fn dm4(_: ()) {}
    |            ^^^^^^^^^^^
@@ -77,17 +59,8 @@ LL |     extern "rust-call" fn dm4(_: ()) {}
    = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
-error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:33:12
-   |
-LL |     extern "efiapi" fn dm10() {}
-   |            ^^^^^^^^
-   |
-   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
-   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
-
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:40:12
+  --> $DIR/feature-gate-abi.rs:36:12
    |
 LL |     extern "rust-intrinsic" fn m1() {}
    |            ^^^^^^^^^^^^^^^^
@@ -95,7 +68,7 @@ LL |     extern "rust-intrinsic" fn m1() {}
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:42:12
+  --> $DIR/feature-gate-abi.rs:38:12
    |
 LL |     extern "platform-intrinsic" fn m2() {}
    |            ^^^^^^^^^^^^^^^^^^^^
@@ -104,7 +77,7 @@ LL |     extern "platform-intrinsic" fn m2() {}
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:44:12
+  --> $DIR/feature-gate-abi.rs:40:12
    |
 LL |     extern "rust-call" fn m4(_: ()) {}
    |            ^^^^^^^^^^^
@@ -112,17 +85,8 @@ LL |     extern "rust-call" fn m4(_: ()) {}
    = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
-error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:45:12
-   |
-LL |     extern "efiapi" fn m10() {}
-   |            ^^^^^^^^
-   |
-   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
-   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
-
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:50:12
+  --> $DIR/feature-gate-abi.rs:45:12
    |
 LL |     extern "rust-intrinsic" fn im1() {}
    |            ^^^^^^^^^^^^^^^^
@@ -130,7 +94,7 @@ LL |     extern "rust-intrinsic" fn im1() {}
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:52:12
+  --> $DIR/feature-gate-abi.rs:47:12
    |
 LL |     extern "platform-intrinsic" fn im2() {}
    |            ^^^^^^^^^^^^^^^^^^^^
@@ -139,7 +103,7 @@ LL |     extern "platform-intrinsic" fn im2() {}
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:54:12
+  --> $DIR/feature-gate-abi.rs:49:12
    |
 LL |     extern "rust-call" fn im4(_: ()) {}
    |            ^^^^^^^^^^^
@@ -147,17 +111,8 @@ LL |     extern "rust-call" fn im4(_: ()) {}
    = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
-error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:55:12
-   |
-LL |     extern "efiapi" fn im10() {}
-   |            ^^^^^^^^
-   |
-   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
-   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
-
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:59:18
+  --> $DIR/feature-gate-abi.rs:53:18
    |
 LL | type A1 = extern "rust-intrinsic" fn();
    |                  ^^^^^^^^^^^^^^^^
@@ -165,7 +120,7 @@ LL | type A1 = extern "rust-intrinsic" fn();
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:60:18
+  --> $DIR/feature-gate-abi.rs:54:18
    |
 LL | type A2 = extern "platform-intrinsic" fn();
    |                  ^^^^^^^^^^^^^^^^^^^^
@@ -174,7 +129,7 @@ LL | type A2 = extern "platform-intrinsic" fn();
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:61:18
+  --> $DIR/feature-gate-abi.rs:55:18
    |
 LL | type A4 = extern "rust-call" fn(_: ());
    |                  ^^^^^^^^^^^
@@ -182,17 +137,8 @@ LL | type A4 = extern "rust-call" fn(_: ());
    = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
-error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:62:19
-   |
-LL | type A10 = extern "efiapi" fn();
-   |                   ^^^^^^^^
-   |
-   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
-   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
-
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:65:8
+  --> $DIR/feature-gate-abi.rs:58:8
    |
 LL | extern "rust-intrinsic" {}
    |        ^^^^^^^^^^^^^^^^
@@ -200,7 +146,7 @@ LL | extern "rust-intrinsic" {}
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:66:8
+  --> $DIR/feature-gate-abi.rs:59:8
    |
 LL | extern "platform-intrinsic" {}
    |        ^^^^^^^^^^^^^^^^^^^^
@@ -209,7 +155,7 @@ LL | extern "platform-intrinsic" {}
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:67:8
+  --> $DIR/feature-gate-abi.rs:60:8
    |
 LL | extern "rust-call" {}
    |        ^^^^^^^^^^^
@@ -217,63 +163,54 @@ LL | extern "rust-call" {}
    = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
-error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:68:8
-   |
-LL | extern "efiapi" {}
-   |        ^^^^^^^^
-   |
-   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
-   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
-
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:25:32
+  --> $DIR/feature-gate-abi.rs:23:32
    |
 LL |     extern "rust-intrinsic" fn m1();
    |                                ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:27:36
+  --> $DIR/feature-gate-abi.rs:25:36
    |
 LL |     extern "platform-intrinsic" fn m2();
    |                                    ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:16:33
+  --> $DIR/feature-gate-abi.rs:15:33
    |
 LL | extern "rust-intrinsic" fn f1() {}
    |                                 ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:18:37
+  --> $DIR/feature-gate-abi.rs:17:37
    |
 LL | extern "platform-intrinsic" fn f2() {}
    |                                     ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:40:37
+  --> $DIR/feature-gate-abi.rs:36:37
    |
 LL |     extern "rust-intrinsic" fn m1() {}
    |                                     ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:42:41
+  --> $DIR/feature-gate-abi.rs:38:41
    |
 LL |     extern "platform-intrinsic" fn m2() {}
    |                                         ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:50:38
+  --> $DIR/feature-gate-abi.rs:45:38
    |
 LL |     extern "rust-intrinsic" fn im1() {}
    |                                      ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:52:42
+  --> $DIR/feature-gate-abi.rs:47:42
    |
 LL |     extern "platform-intrinsic" fn im2() {}
    |                                          ^^
 
-error: aborting due to 34 previous errors
+error: aborting due to 27 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-custom_mir.rs b/src/test/ui/feature-gates/feature-gate-custom_mir.rs
new file mode 100644
index 00000000000..0126dde2f7d
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-custom_mir.rs
@@ -0,0 +1,12 @@
+#![feature(core_intrinsics)]
+
+extern crate core;
+
+#[custom_mir(dialect = "built")] //~ ERROR the `#[custom_mir]` attribute is just used for the Rust test suite
+pub fn foo(_x: i32) -> i32 {
+    0
+}
+
+fn main() {
+    assert_eq!(2, foo(2));
+}
diff --git a/src/test/ui/feature-gates/feature-gate-custom_mir.stderr b/src/test/ui/feature-gates/feature-gate-custom_mir.stderr
new file mode 100644
index 00000000000..3c149d30d82
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-custom_mir.stderr
@@ -0,0 +1,11 @@
+error[E0658]: the `#[custom_mir]` attribute is just used for the Rust test suite
+  --> $DIR/feature-gate-custom_mir.rs:5:1
+   |
+LL | #[custom_mir(dialect = "built")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(custom_mir)]` 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/generator/auto-trait-regions.stderr b/src/test/ui/generator/auto-trait-regions.stderr
index 23324af6171..0b1f34aeb96 100644
--- a/src/test/ui/generator/auto-trait-regions.stderr
+++ b/src/test/ui/generator/auto-trait-regions.stderr
@@ -4,7 +4,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |         let a = A(&mut true, &mut true, No);
    |                        ^^^^                - temporary value is freed at the end of this statement
    |                        |
-   |                        creates a temporary which is freed while still in use
+   |                        creates a temporary value which is freed while still in use
 ...
 LL |         assert_foo(a);
    |                    - borrow later used here
@@ -17,7 +17,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |         let a = A(&mut true, &mut true, No);
    |                                   ^^^^     - temporary value is freed at the end of this statement
    |                                   |
-   |                                   creates a temporary which is freed while still in use
+   |                                   creates a temporary value which is freed while still in use
 ...
 LL |         assert_foo(a);
    |                    - borrow later used here
diff --git a/src/test/ui/generic-associated-types/bugs/hrtb-implied-1.stderr b/src/test/ui/generic-associated-types/bugs/hrtb-implied-1.stderr
index 414999881d4..1c9abc4e837 100644
--- a/src/test/ui/generic-associated-types/bugs/hrtb-implied-1.stderr
+++ b/src/test/ui/generic-associated-types/bugs/hrtb-implied-1.stderr
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/hrtb-implied-1.rs:31:22
    |
 LL |     let slice = &mut ();
-   |                      ^^ creates a temporary which is freed while still in use
+   |                      ^^ creates a temporary value which is freed while still in use
 ...
 LL |     print_items::<WindowsMut<'_>>(windows);
    |     -------------------------------------- argument requires that borrow lasts for `'static`
diff --git a/src/test/ui/issues/issue-47184.stderr b/src/test/ui/issues/issue-47184.stderr
index f97713b4ac4..c2c7df7a333 100644
--- a/src/test/ui/issues/issue-47184.stderr
+++ b/src/test/ui/issues/issue-47184.stderr
@@ -4,7 +4,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let _vec: Vec<&'static String> = vec![&String::new()];
    |               --------------------         ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
    |               |                            |
-   |               |                            creates a temporary which is freed while still in use
+   |               |                            creates a temporary value which is freed while still in use
    |               type annotation requires that borrow lasts for `'static`
 
 error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-52049.stderr b/src/test/ui/issues/issue-52049.stderr
index 55929d85da4..b25dbd1cb8b 100644
--- a/src/test/ui/issues/issue-52049.stderr
+++ b/src/test/ui/issues/issue-52049.stderr
@@ -4,7 +4,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     foo(&unpromotable(5u32));
    |     -----^^^^^^^^^^^^^^^^^^-
    |     |    |
-   |     |    creates a temporary which is freed while still in use
+   |     |    creates a temporary value which is freed while still in use
    |     argument requires that borrow lasts for `'static`
 LL | }
    | - temporary value is freed at the end of this statement
diff --git a/src/test/ui/lifetimes/borrowck-let-suggestion.stderr b/src/test/ui/lifetimes/borrowck-let-suggestion.stderr
index bbf04c98436..987b051b111 100644
--- a/src/test/ui/lifetimes/borrowck-let-suggestion.stderr
+++ b/src/test/ui/lifetimes/borrowck-let-suggestion.stderr
@@ -4,7 +4,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let mut x = vec![1].iter();
    |                 ^^^^^^^       - temporary value is freed at the end of this statement
    |                 |
-   |                 creates a temporary which is freed while still in use
+   |                 creates a temporary value which is freed while still in use
 LL |
 LL |     x.use_mut();
    |     ----------- borrow later used here
diff --git a/src/test/ui/nll/borrowed-temporary-error.stderr b/src/test/ui/nll/borrowed-temporary-error.stderr
index 2c6bd92641f..89781d96fab 100644
--- a/src/test/ui/nll/borrowed-temporary-error.stderr
+++ b/src/test/ui/nll/borrowed-temporary-error.stderr
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/borrowed-temporary-error.rs:8:10
    |
 LL |         &(v,)
-   |          ^^^^ creates a temporary which is freed while still in use
+   |          ^^^^ creates a temporary value which is freed while still in use
 LL |
 LL |     });
    |       - temporary value is freed at the end of this statement
diff --git a/src/test/ui/nll/issue-57265-return-type-wf-check.stderr b/src/test/ui/nll/issue-57265-return-type-wf-check.stderr
index 20add62b91d..bb45575fa64 100644
--- a/src/test/ui/nll/issue-57265-return-type-wf-check.stderr
+++ b/src/test/ui/nll/issue-57265-return-type-wf-check.stderr
@@ -4,7 +4,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let (_, z) = foo(&"hello".to_string());
    |                  -----^^^^^^^^^^^^^^^^^^^-- temporary value is freed at the end of this statement
    |                  |    |
-   |                  |    creates a temporary which is freed while still in use
+   |                  |    creates a temporary value which is freed while still in use
    |                  argument requires that borrow lasts for `'static`
 
 error: aborting due to previous error
diff --git a/src/test/ui/nll/user-annotations/patterns.stderr b/src/test/ui/nll/user-annotations/patterns.stderr
index 60d6e6db363..de6f8f80fe2 100644
--- a/src/test/ui/nll/user-annotations/patterns.stderr
+++ b/src/test/ui/nll/user-annotations/patterns.stderr
@@ -76,7 +76,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let _: Vec<&'static String> = vec![&String::new()];
    |            --------------------         ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
    |            |                            |
-   |            |                            creates a temporary which is freed while still in use
+   |            |                            creates a temporary value which is freed while still in use
    |            type annotation requires that borrow lasts for `'static`
 
 error[E0716]: temporary value dropped while borrowed
@@ -85,7 +85,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let (_, a): (Vec<&'static String>, _) = (vec![&String::new()], 44);
    |                 -------------------------          ^^^^^^^^^^^^^      - temporary value is freed at the end of this statement
    |                 |                                  |
-   |                 |                                  creates a temporary which is freed while still in use
+   |                 |                                  creates a temporary value which is freed while still in use
    |                 type annotation requires that borrow lasts for `'static`
 
 error[E0716]: temporary value dropped while borrowed
@@ -94,7 +94,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let (_a, b): (Vec<&'static String>, _) = (vec![&String::new()], 44);
    |                  -------------------------          ^^^^^^^^^^^^^      - temporary value is freed at the end of this statement
    |                  |                                  |
-   |                  |                                  creates a temporary which is freed while still in use
+   |                  |                                  creates a temporary value which is freed while still in use
    |                  type annotation requires that borrow lasts for `'static`
 
 error[E0597]: `x` does not live long enough
diff --git a/src/test/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr b/src/test/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr
index 4971263af08..fc1be052fb7 100644
--- a/src/test/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr
+++ b/src/test/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr
@@ -4,7 +4,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let phantom_pinned = identity(pin!(PhantomPinned));
    |                                   ^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
    |                                   |
-   |                                   creates a temporary which is freed while still in use
+   |                                   creates a temporary value which is freed while still in use
 LL |
 LL |     stuff(phantom_pinned)
    |           -------------- borrow later used here
@@ -18,7 +18,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let phantom_pinned = {
    |         -------------- borrow later stored here
 LL |         let phantom_pinned = pin!(PhantomPinned);
-   |                              ^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |                              ^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
 ...
 LL |     };
    |     - temporary value is freed at the end of this statement
diff --git a/src/test/ui/regions/regions-free-region-ordering-caller1.stderr b/src/test/ui/regions/regions-free-region-ordering-caller1.stderr
index 8042b1740b1..8ef7e22536b 100644
--- a/src/test/ui/regions/regions-free-region-ordering-caller1.stderr
+++ b/src/test/ui/regions/regions-free-region-ordering-caller1.stderr
@@ -5,7 +5,7 @@ LL | fn call1<'a>(x: &'a usize) {
    |          -- lifetime `'a` defined here
 ...
 LL |     let z: &'a & usize = &(&y);
-   |            -----------    ^^^^ creates a temporary which is freed while still in use
+   |            -----------    ^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'a`
 ...
diff --git a/src/test/ui/regions/regions-var-type-out-of-scope.stderr b/src/test/ui/regions/regions-var-type-out-of-scope.stderr
index 476e82f046f..c32bbe0ee1f 100644
--- a/src/test/ui/regions/regions-var-type-out-of-scope.stderr
+++ b/src/test/ui/regions/regions-var-type-out-of-scope.stderr
@@ -4,7 +4,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |         x = &id(3);
    |              ^^^^^- temporary value is freed at the end of this statement
    |              |
-   |              creates a temporary which is freed while still in use
+   |              creates a temporary value which is freed while still in use
 LL |         assert_eq!(*x, 3);
    |         ----------------- borrow later used here
    |
diff --git a/src/test/ui/span/borrowck-let-suggestion-suffixes.rs b/src/test/ui/span/borrowck-let-suggestion-suffixes.rs
index 6240f103c99..18abfb5c3fb 100644
--- a/src/test/ui/span/borrowck-let-suggestion-suffixes.rs
+++ b/src/test/ui/span/borrowck-let-suggestion-suffixes.rs
@@ -18,7 +18,7 @@ fn f() {
 
     v3.push(&id('x'));           // statement 6
     //~^ ERROR temporary value dropped while borrowed
-    //~| NOTE creates a temporary which is freed while still in use
+    //~| NOTE creates a temporary value which is freed while still in use
     //~| NOTE temporary value is freed at the end of this statement
     //~| HELP consider using a `let` binding to create a longer lived value
 
@@ -28,7 +28,7 @@ fn f() {
 
         v4.push(&id('y'));
         //~^ ERROR temporary value dropped while borrowed
-        //~| NOTE creates a temporary which is freed while still in use
+        //~| NOTE creates a temporary value which is freed while still in use
         //~| NOTE temporary value is freed at the end of this statement
         //~| NOTE consider using a `let` binding to create a longer lived value
         v4.use_ref();
@@ -39,7 +39,7 @@ fn f() {
 
     v5.push(&id('z'));
     //~^ ERROR temporary value dropped while borrowed
-    //~| NOTE creates a temporary which is freed while still in use
+    //~| NOTE creates a temporary value which is freed while still in use
     //~| NOTE temporary value is freed at the end of this statement
     //~| HELP consider using a `let` binding to create a longer lived value
 
diff --git a/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr b/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr
index a236dab3ae5..2dc29a78d20 100644
--- a/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr
+++ b/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr
@@ -16,7 +16,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     v3.push(&id('x'));           // statement 6
    |              ^^^^^^^ - temporary value is freed at the end of this statement
    |              |
-   |              creates a temporary which is freed while still in use
+   |              creates a temporary value which is freed while still in use
 ...
 LL |     (v1, v2, v3, /* v4 is above. */ v5).use_ref();
    |              -- borrow later used here
@@ -33,7 +33,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |         v4.push(&id('y'));
    |                  ^^^^^^^ - temporary value is freed at the end of this statement
    |                  |
-   |                  creates a temporary which is freed while still in use
+   |                  creates a temporary value which is freed while still in use
 ...
 LL |         v4.use_ref();
    |         ------------ borrow later used here
@@ -46,7 +46,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     v5.push(&id('z'));
    |              ^^^^^^^ - temporary value is freed at the end of this statement
    |              |
-   |              creates a temporary which is freed while still in use
+   |              creates a temporary value which is freed while still in use
 ...
 LL |     (v1, v2, v3, /* v4 is above. */ v5).use_ref();
    |                                     -- borrow later used here
diff --git a/src/test/ui/span/borrowck-ref-into-rvalue.stderr b/src/test/ui/span/borrowck-ref-into-rvalue.stderr
index cb5289d24b4..25e344fedfb 100644
--- a/src/test/ui/span/borrowck-ref-into-rvalue.stderr
+++ b/src/test/ui/span/borrowck-ref-into-rvalue.stderr
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/borrowck-ref-into-rvalue.rs:4:11
    |
 LL |     match Some("Hello".to_string()) {
-   |           ^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
 ...
 LL |     }
    |     - temporary value is freed at the end of this statement
diff --git a/src/test/ui/span/issue-15480.stderr b/src/test/ui/span/issue-15480.stderr
index 460ad9ac744..d9cce2254dd 100644
--- a/src/test/ui/span/issue-15480.stderr
+++ b/src/test/ui/span/issue-15480.stderr
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/issue-15480.rs:6:10
    |
 LL |         &id(3)
-   |          ^^^^^ creates a temporary which is freed while still in use
+   |          ^^^^^ creates a temporary value which is freed while still in use
 LL |     ];
    |      - temporary value is freed at the end of this statement
 ...
diff --git a/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.stderr b/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.stderr
index ba0c45acf23..81e858fa0ce 100644
--- a/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.stderr
+++ b/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.stderr
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/regions-close-over-borrowed-ref-in-obj.rs:12:27
    |
 LL |         let ss: &isize = &id(1);
-   |                           ^^^^^ creates a temporary which is freed while still in use
+   |                           ^^^^^ creates a temporary value which is freed while still in use
 ...
 LL |     }
    |     - temporary value is freed at the end of this statement
diff --git a/src/test/ui/span/slice-borrow.stderr b/src/test/ui/span/slice-borrow.stderr
index 27df25be3fa..b70bf69d688 100644
--- a/src/test/ui/span/slice-borrow.stderr
+++ b/src/test/ui/span/slice-borrow.stderr
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/slice-borrow.rs:6:28
    |
 LL |         let x: &[isize] = &vec![1, 2, 3, 4, 5];
-   |                            ^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |                            ^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
 ...
 LL |     }
    |     - temporary value is freed at the end of this statement
diff --git a/src/test/ui/static/static-drop-scope.stderr b/src/test/ui/static/static-drop-scope.stderr
index 112bfc00304..cedcb736794 100644
--- a/src/test/ui/static/static-drop-scope.stderr
+++ b/src/test/ui/static/static-drop-scope.stderr
@@ -13,7 +13,7 @@ LL | static PROMOTION_FAIL_S: Option<&'static WithDtor> = Some(&WithDtor);
    |                                                      ------^^^^^^^^-
    |                                                      |     |       |
    |                                                      |     |       temporary value is freed at the end of this statement
-   |                                                      |     creates a temporary which is freed while still in use
+   |                                                      |     creates a temporary value which is freed while still in use
    |                                                      using this value as a static requires that borrow lasts for `'static`
 
 error[E0493]: destructor of `WithDtor` cannot be evaluated at compile-time
@@ -31,7 +31,7 @@ LL | const PROMOTION_FAIL_C: Option<&'static WithDtor> = Some(&WithDtor);
    |                                                     ------^^^^^^^^-
    |                                                     |     |       |
    |                                                     |     |       temporary value is freed at the end of this statement
-   |                                                     |     creates a temporary which is freed while still in use
+   |                                                     |     creates a temporary value which is freed while still in use
    |                                                     using this value as a constant requires that borrow lasts for `'static`
 
 error[E0493]: destructor of `(WithDtor, i32)` cannot be evaluated at compile-time
diff --git a/src/test/ui/static/static-reference-to-fn-2.stderr b/src/test/ui/static/static-reference-to-fn-2.stderr
index ff15884bd44..133d8ec2e1e 100644
--- a/src/test/ui/static/static-reference-to-fn-2.stderr
+++ b/src/test/ui/static/static-reference-to-fn-2.stderr
@@ -6,7 +6,7 @@ LL | fn state1(self_: &mut StateMachineIter) -> Option<&'static str> {
 LL |     self_.statefn = &id(state2 as StateMachineFunc);
    |     -----------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
    |     |                |
-   |     |                creates a temporary which is freed while still in use
+   |     |                creates a temporary value which is freed while still in use
    |     assignment requires that borrow lasts for `'1`
 
 error[E0716]: temporary value dropped while borrowed
@@ -17,7 +17,7 @@ LL | fn state2(self_: &mut StateMachineIter) -> Option<(&'static str)> {
 LL |     self_.statefn = &id(state3 as StateMachineFunc);
    |     -----------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
    |     |                |
-   |     |                creates a temporary which is freed while still in use
+   |     |                creates a temporary value which is freed while still in use
    |     assignment requires that borrow lasts for `'1`
 
 error[E0716]: temporary value dropped while borrowed
@@ -28,7 +28,7 @@ LL | fn state3(self_: &mut StateMachineIter) -> Option<(&'static str)> {
 LL |     self_.statefn = &id(finished as StateMachineFunc);
    |     -----------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
    |     |                |
-   |     |                creates a temporary which is freed while still in use
+   |     |                creates a temporary value which is freed while still in use
    |     assignment requires that borrow lasts for `'1`
 
 error[E0515]: cannot return value referencing temporary value
diff --git a/src/test/ui/static/static-region-bound.stderr b/src/test/ui/static/static-region-bound.stderr
index 15261259ed4..1a607e3c014 100644
--- a/src/test/ui/static/static-region-bound.stderr
+++ b/src/test/ui/static/static-region-bound.stderr
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/static-region-bound.rs:10:14
    |
 LL |     let x = &id(3);
-   |              ^^^^^ creates a temporary which is freed while still in use
+   |              ^^^^^ creates a temporary value which is freed while still in use
 LL |     f(x);
    |     ---- argument requires that borrow lasts for `'static`
 LL | }
diff --git a/src/test/ui/statics/issue-44373.stderr b/src/test/ui/statics/issue-44373.stderr
index 6f92fbb1eb6..2d29dec888e 100644
--- a/src/test/ui/statics/issue-44373.stderr
+++ b/src/test/ui/statics/issue-44373.stderr
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/issue-44373.rs:4:42
    |
 LL |     let _val: &'static [&'static u32] = &[&FOO];
-   |               -----------------------    ^^^^^^ creates a temporary which is freed while still in use
+   |               -----------------------    ^^^^^^ creates a temporary value which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
 LL | }
diff --git a/src/test/ui/target-feature/tied-features-cli.one.stderr b/src/test/ui/target-feature/tied-features-cli.one.stderr
index 0cc901eecaa..b4b50d98192 100644
--- a/src/test/ui/target-feature/tied-features-cli.one.stderr
+++ b/src/test/ui/target-feature/tied-features-cli.one.stderr
@@ -1,4 +1,4 @@
-error: target features paca, pacg must all be enabled or disabled together
+error: the target features paca, pacg must all be either enabled or disabled together
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/target-feature/tied-features-cli.three.stderr b/src/test/ui/target-feature/tied-features-cli.three.stderr
index 0cc901eecaa..b4b50d98192 100644
--- a/src/test/ui/target-feature/tied-features-cli.three.stderr
+++ b/src/test/ui/target-feature/tied-features-cli.three.stderr
@@ -1,4 +1,4 @@
-error: target features paca, pacg must all be enabled or disabled together
+error: the target features paca, pacg must all be either enabled or disabled together
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/target-feature/tied-features-cli.two.stderr b/src/test/ui/target-feature/tied-features-cli.two.stderr
index 0cc901eecaa..b4b50d98192 100644
--- a/src/test/ui/target-feature/tied-features-cli.two.stderr
+++ b/src/test/ui/target-feature/tied-features-cli.two.stderr
@@ -1,4 +1,4 @@
-error: target features paca, pacg must all be enabled or disabled together
+error: the target features paca, pacg must all be either enabled or disabled together
 
 error: aborting due to previous error