about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-01-29 00:58:43 +0000
committerbors <bors@rust-lang.org>2021-01-29 00:58:43 +0000
commit74500b99783d126e330184f0392a78f8b93b73ef (patch)
tree4674c1335afecd916d742d31ab0e29169d10f1a0
parentb05fd2a15de7c9e50110e9ed4c01f114be215739 (diff)
parent2b4fa3d2118110c21e55b899ebfc9a0fadee50fd (diff)
downloadrust-74500b99783d126e330184f0392a78f8b93b73ef.tar.gz
rust-74500b99783d126e330184f0392a78f8b93b73ef.zip
Auto merge of #81493 - JohnTitor:rollup-sa4m4zh, r=JohnTitor
Rollup of 10 pull requests

Successful merges:

 - #79570 (rustc: Stabilize `-Zrun-dsymutil` as `-Csplit-debuginfo`)
 - #79819 (Add `SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` lint)
 - #79991 (rustdoc: Render HRTB correctly for bare functions)
 - #80215 (Use -target when linking binaries for Mac Catalyst)
 - #81158 (Point to span of upvar making closure FnMut)
 - #81176 (Improve safety of `LateContext::qpath_res`)
 - #81287 (Split rustdoc JSON types into separately versioned crate)
 - #81306 (Fuse inner iterator in FlattenCompat and improve related tests)
 - #81333 (clean up some const error reporting around promoteds)
 - #81459 (Fix rustdoc text selection for page titles)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--Cargo.lock9
-rw-r--r--Cargo.toml1
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/back/lto.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs29
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs11
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs7
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs93
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs20
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/constant.rs7
-rw-r--r--compiler/rustc_expand/Cargo.toml1
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs14
-rw-r--r--compiler/rustc_interface/src/tests.rs4
-rw-r--r--compiler/rustc_lint/src/context.rs8
-rw-r--r--compiler/rustc_lint/src/late.rs4
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs48
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs56
-rw-r--r--compiler/rustc_mir/src/const_eval/eval_queries.rs102
-rw-r--r--compiler/rustc_resolve/src/macros.rs2
-rw-r--r--compiler/rustc_session/src/config.rs45
-rw-r--r--compiler/rustc_session/src/options.rs35
-rw-r--r--compiler/rustc_session/src/session.rs10
-rw-r--r--compiler/rustc_target/src/spec/apple_base.rs6
-rw-r--r--compiler/rustc_target/src/spec/mod.rs82
-rw-r--r--compiler/rustc_target/src/spec/msvc_base.rs6
-rw-r--r--library/core/src/iter/adapters/flatten.rs16
-rw-r--r--library/core/tests/iter/adapters/flatten.rs17
-rw-r--r--src/bootstrap/bootstrap.py1
-rw-r--r--src/bootstrap/builder.rs20
-rw-r--r--src/doc/rustc/src/codegen-options/index.md30
-rw-r--r--src/librustdoc/Cargo.toml1
-rw-r--r--src/librustdoc/html/format.rs21
-rw-r--r--src/librustdoc/html/render/mod.rs64
-rw-r--r--src/librustdoc/json/conversions.rs83
-rw-r--r--src/librustdoc/json/mod.rs21
-rw-r--r--src/rustdoc-json-types/Cargo.toml11
-rw-r--r--src/rustdoc-json-types/README.md12
-rw-r--r--src/rustdoc-json-types/lib.rs (renamed from src/librustdoc/json/types.rs)10
-rw-r--r--src/test/run-make-fulldeps/split-debuginfo/Makefile59
-rw-r--r--src/test/run-make-fulldeps/split-debuginfo/foo.rs1
-rw-r--r--src/test/run-make-fulldeps/split-dwarf/Makefile2
-rw-r--r--src/test/rustdoc/fn-type.rs15
-rw-r--r--src/test/rustdoc/for-lifetime.rs14
-rw-r--r--src/test/ui/associated-consts/defaults-not-assumed-fail.rs2
-rw-r--r--src/test/ui/associated-consts/defaults-not-assumed-fail.stderr10
-rw-r--r--src/test/ui/backtrace-apple-no-dsymutil.rs30
-rw-r--r--src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr4
-rw-r--r--src/test/ui/closures/issue-80313-mutable-borrow-in-closure.rs7
-rw-r--r--src/test/ui/closures/issue-80313-mutable-borrow-in-closure.stderr14
-rw-r--r--src/test/ui/closures/issue-80313-mutable-borrow-in-move-closure.rs7
-rw-r--r--src/test/ui/closures/issue-80313-mutable-borrow-in-move-closure.stderr14
-rw-r--r--src/test/ui/closures/issue-80313-mutation-in-closure.rs7
-rw-r--r--src/test/ui/closures/issue-80313-mutation-in-closure.stderr14
-rw-r--r--src/test/ui/closures/issue-80313-mutation-in-move-closure.rs7
-rw-r--r--src/test/ui/closures/issue-80313-mutation-in-move-closure.stderr14
-rw-r--r--src/test/ui/consts/const-eval/conditional_array_execution.stderr2
-rw-r--r--src/test/ui/consts/const-eval/const-eval-query-stack.rs2
-rw-r--r--src/test/ui/consts/const-eval/const-eval-query-stack.stderr8
-rw-r--r--src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs4
-rw-r--r--src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr20
-rw-r--r--src/test/ui/consts/const-eval/issue-43197.rs4
-rw-r--r--src/test/ui/consts/const-eval/issue-43197.stderr4
-rw-r--r--src/test/ui/consts/const-eval/issue-44578.rs2
-rw-r--r--src/test/ui/consts/const-eval/issue-44578.stderr2
-rw-r--r--src/test/ui/consts/const-eval/issue-50814-2.stderr8
-rw-r--r--src/test/ui/consts/const-eval/issue-50814.stderr8
-rw-r--r--src/test/ui/consts/const_unsafe_unreachable_ub.stderr10
-rw-r--r--src/test/ui/consts/issue-55878.stderr7
-rw-r--r--src/test/ui/lint/semicolon-in-expressions-from-macros/allow-semicolon-in-expressions-from-macros.rs15
-rw-r--r--src/test/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.rs30
-rw-r--r--src/test/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr33
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.stderr4
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.stderr4
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.stderr4
-rw-r--r--src/tools/clippy/clippy_lints/src/default.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/drop_forget_ref.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/exit.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/functions.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/let_if_seq.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_strip.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/mem_forget.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/no_effect.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/to_string_in_display.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/types.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/mod.rs13
-rw-r--r--src/tools/compiletest/src/runtest.rs4
-rw-r--r--src/tools/tidy/src/ui_tests.rs2
90 files changed, 979 insertions, 442 deletions
diff --git a/Cargo.lock b/Cargo.lock
index fb5ae6ce663..a4ba7704426 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3746,6 +3746,7 @@ dependencies = [
  "rustc_errors",
  "rustc_feature",
  "rustc_lexer",
+ "rustc_lint_defs",
  "rustc_macros",
  "rustc_parse",
  "rustc_serialize",
@@ -4391,6 +4392,7 @@ dependencies = [
  "pulldown-cmark 0.8.0",
  "regex",
  "rustc-rayon",
+ "rustdoc-json-types",
  "serde",
  "serde_json",
  "smallvec 1.4.2",
@@ -4398,6 +4400,13 @@ dependencies = [
 ]
 
 [[package]]
+name = "rustdoc-json-types"
+version = "0.1.0"
+dependencies = [
+ "serde",
+]
+
+[[package]]
 name = "rustdoc-themes"
 version = "0.1.0"
 
diff --git a/Cargo.toml b/Cargo.toml
index 5bd1147cad5..f3b2e0f740d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,6 +4,7 @@ members = [
   "compiler/rustc",
   "library/std",
   "library/test",
+  "src/rustdoc-json-types",
   "src/tools/cargotest",
   "src/tools/clippy",
   "src/tools/compiletest",
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index beff84fb2e2..5702832bcb6 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -134,11 +134,9 @@ pub(crate) fn codegen_constant<'tcx>(
             {
                 Ok(const_val) => const_val,
                 Err(_) => {
-                    if promoted.is_none() {
-                        fx.tcx
-                            .sess
-                            .span_err(constant.span, "erroneous constant encountered");
-                    }
+                    fx.tcx
+                        .sess
+                        .span_err(constant.span, "erroneous constant encountered");
                     return crate::trap::trap_unreachable_ret_value(
                         fx,
                         fx.layout_of(const_.ty),
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index 29415973ed0..5effe687528 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -732,10 +732,7 @@ pub unsafe fn optimize_thin_module(
     let diag_handler = cgcx.create_diag_handler();
 
     let module_name = &thin_module.shared.module_names[thin_module.idx];
-    let split_dwarf_file = cgcx
-        .output_filenames
-        .split_dwarf_filename(cgcx.split_dwarf_kind, Some(module_name.to_str().unwrap()));
-    let tm_factory_config = TargetMachineFactoryConfig { split_dwarf_file };
+    let tm_factory_config = TargetMachineFactoryConfig::new(cgcx, module_name.to_str().unwrap());
     let tm =
         (cgcx.tm_factory)(tm_factory_config).map_err(|e| write::llvm_err(&diag_handler, &e))?;
 
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index e225730dce0..326ae354ccf 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -23,13 +23,11 @@ use rustc_fs_util::{link_or_copy, path_to_c_string};
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::bug;
 use rustc_middle::ty::TyCtxt;
-use rustc_session::config::{
-    self, Lto, OutputType, Passes, SanitizerSet, SplitDwarfKind, SwitchWithOptPath,
-};
+use rustc_session::config::{self, Lto, OutputType, Passes, SanitizerSet, SwitchWithOptPath};
 use rustc_session::Session;
 use rustc_span::symbol::sym;
 use rustc_span::InnerSpan;
-use rustc_target::spec::{CodeModel, RelocModel};
+use rustc_target::spec::{CodeModel, RelocModel, SplitDebuginfo};
 use tracing::debug;
 
 use libc::{c_char, c_int, c_uint, c_void, size_t};
@@ -93,9 +91,12 @@ pub fn create_informational_target_machine(sess: &Session) -> &'static mut llvm:
 }
 
 pub fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> &'static mut llvm::TargetMachine {
-    let split_dwarf_file = tcx
-        .output_filenames(LOCAL_CRATE)
-        .split_dwarf_filename(tcx.sess.opts.debugging_opts.split_dwarf, Some(mod_name));
+    let split_dwarf_file = if tcx.sess.target_can_use_split_dwarf() {
+        tcx.output_filenames(LOCAL_CRATE)
+            .split_dwarf_filename(tcx.sess.split_debuginfo(), Some(mod_name))
+    } else {
+        None
+    };
     let config = TargetMachineFactoryConfig { split_dwarf_file };
     target_machine_factory(&tcx.sess, tcx.backend_optimization_level(LOCAL_CRATE))(config)
         .unwrap_or_else(|err| llvm_err(tcx.sess.diagnostic(), &err).raise())
@@ -838,11 +839,17 @@ pub(crate) unsafe fn codegen(
                     .generic_activity_with_arg("LLVM_module_codegen_emit_obj", &module.name[..]);
 
                 let dwo_out = cgcx.output_filenames.temp_path_dwo(module_name);
-                let dwo_out = match cgcx.split_dwarf_kind {
+                let dwo_out = match cgcx.split_debuginfo {
                     // Don't change how DWARF is emitted in single mode (or when disabled).
-                    SplitDwarfKind::None | SplitDwarfKind::Single => None,
+                    SplitDebuginfo::Off | SplitDebuginfo::Packed => None,
                     // Emit (a subset of the) DWARF into a separate file in split mode.
-                    SplitDwarfKind::Split => Some(dwo_out.as_path()),
+                    SplitDebuginfo::Unpacked => {
+                        if cgcx.target_can_use_split_dwarf {
+                            Some(dwo_out.as_path())
+                        } else {
+                            None
+                        }
+                    }
                 };
 
                 with_codegen(tm, llmod, config.no_builtins, |cpm| {
@@ -880,7 +887,7 @@ pub(crate) unsafe fn codegen(
 
     Ok(module.into_compiled_module(
         config.emit_obj != EmitObj::None,
-        cgcx.split_dwarf_kind == SplitDwarfKind::Split,
+        cgcx.target_can_use_split_dwarf && cgcx.split_debuginfo == SplitDebuginfo::Unpacked,
         config.emit_bc,
         &cgcx.output_filenames,
     ))
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 3a4e1492af3..6e7c0b3e347 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -995,10 +995,13 @@ pub fn compile_unit_metadata(
     let flags = "\0";
 
     let out_dir = &tcx.output_filenames(LOCAL_CRATE).out_directory;
-    let split_name = tcx
-        .output_filenames(LOCAL_CRATE)
-        .split_dwarf_filename(tcx.sess.opts.debugging_opts.split_dwarf, Some(codegen_unit_name))
-        .unwrap_or_default();
+    let split_name = if tcx.sess.target_can_use_split_dwarf() {
+        tcx.output_filenames(LOCAL_CRATE)
+            .split_dwarf_filename(tcx.sess.split_debuginfo(), Some(codegen_unit_name))
+    } else {
+        None
+    }
+    .unwrap_or_default();
     let out_dir = out_dir.to_str().unwrap();
     let split_name = split_name.to_str().unwrap();
 
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 92ac770aca5..d11c1592f99 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -351,12 +351,7 @@ impl ModuleLlvm {
         unsafe {
             let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
             let llmod_raw = back::lto::parse_module(llcx, name, buffer, handler)?;
-
-            let split_dwarf_file = cgcx
-                .output_filenames
-                .split_dwarf_filename(cgcx.split_dwarf_kind, Some(name.to_str().unwrap()));
-            let tm_factory_config = TargetMachineFactoryConfig { split_dwarf_file };
-
+            let tm_factory_config = TargetMachineFactoryConfig::new(&cgcx, name.to_str().unwrap());
             let tm = match (cgcx.tm_factory)(tm_factory_config) {
                 Ok(m) => m,
                 Err(e) => {
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 72e049b6d74..8bc4e644223 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -14,7 +14,7 @@ use rustc_session::utils::NativeLibKind;
 use rustc_session::{filesearch, Session};
 use rustc_span::symbol::Symbol;
 use rustc_target::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
-use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor};
+use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor, SplitDebuginfo};
 use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, Target};
 
 use super::archive::ArchiveBuilder;
@@ -99,9 +99,6 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
                         path.as_ref(),
                         target_cpu,
                     );
-                    if sess.opts.debugging_opts.split_dwarf == config::SplitDwarfKind::Split {
-                        link_dwarf_object(sess, &out_filename);
-                    }
                 }
             }
             if sess.opts.json_artifact_notifications {
@@ -828,29 +825,43 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
         }
     }
 
-    // On macOS, debuggers need this utility to get run to do some munging of
-    // the symbols. Note, though, that if the object files are being preserved
-    // for their debug information there's no need for us to run dsymutil.
-    if sess.target.is_like_osx
-        && sess.opts.debuginfo != DebugInfo::None
-        && !preserve_objects_for_their_debuginfo(sess)
-    {
-        let prog = Command::new("dsymutil").arg(out_filename).output();
-        match prog {
-            Ok(prog) => {
-                if !prog.status.success() {
-                    let mut output = prog.stderr.clone();
-                    output.extend_from_slice(&prog.stdout);
-                    sess.struct_warn(&format!(
-                        "processing debug info with `dsymutil` failed: {}",
-                        prog.status
-                    ))
-                    .note(&escape_string(&output))
-                    .emit();
+    match sess.split_debuginfo() {
+        // If split debug information is disabled or located in individual files
+        // there's nothing to do here.
+        SplitDebuginfo::Off | SplitDebuginfo::Unpacked => {}
+
+        // If packed split-debuginfo is requested, but the final compilation
+        // doesn't actually have any debug information, then we skip this step.
+        SplitDebuginfo::Packed if sess.opts.debuginfo == DebugInfo::None => {}
+
+        // On macOS the external `dsymutil` tool is used to create the packed
+        // debug information. Note that this will read debug information from
+        // the objects on the filesystem which we'll clean up later.
+        SplitDebuginfo::Packed if sess.target.is_like_osx => {
+            let prog = Command::new("dsymutil").arg(out_filename).output();
+            match prog {
+                Ok(prog) => {
+                    if !prog.status.success() {
+                        let mut output = prog.stderr.clone();
+                        output.extend_from_slice(&prog.stdout);
+                        sess.struct_warn(&format!(
+                            "processing debug info with `dsymutil` failed: {}",
+                            prog.status
+                        ))
+                        .note(&escape_string(&output))
+                        .emit();
+                    }
                 }
+                Err(e) => sess.fatal(&format!("unable to run `dsymutil`: {}", e)),
             }
-            Err(e) => sess.fatal(&format!("unable to run `dsymutil`: {}", e)),
         }
+
+        // On MSVC packed debug information is produced by the linker itself so
+        // there's no need to do anything else here.
+        SplitDebuginfo::Packed if sess.target.is_like_msvc => {}
+
+        // ... and otherwise we're processing a `*.dwp` packed dwarf file.
+        SplitDebuginfo::Packed => link_dwarf_object(sess, &out_filename),
     }
 }
 
@@ -1050,28 +1061,9 @@ fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool {
         return false;
     }
 
-    // Single mode keeps debuginfo in the same object file, but in such a way that it it skipped
-    // by the linker - so it's expected that when codegen units are linked together that this
-    // debuginfo would be lost without keeping around the temps.
-    if sess.opts.debugging_opts.split_dwarf == config::SplitDwarfKind::Single {
-        return true;
-    }
-
-    // If we're on OSX then the equivalent of split dwarf is turned on by
-    // default. The final executable won't actually have any debug information
-    // except it'll have pointers to elsewhere. Historically we've always run
-    // `dsymutil` to "link all the dwarf together" but this is actually sort of
-    // a bummer for incremental compilation! (the whole point of split dwarf is
-    // that you don't do this sort of dwarf link).
-    //
-    // Basically as a result this just means that if we're on OSX and we're
-    // *not* running dsymutil then the object files are the only source of truth
-    // for debug information, so we must preserve them.
-    if sess.target.is_like_osx {
-        return !sess.opts.debugging_opts.run_dsymutil;
-    }
-
-    false
+    // "unpacked" split debuginfo means that we leave object files as the
+    // debuginfo is found in the original object files themselves
+    sess.split_debuginfo() == SplitDebuginfo::Unpacked
 }
 
 pub fn archive_search_paths(sess: &Session) -> Vec<PathBuf> {
@@ -2211,8 +2203,13 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
             return;
         }
     };
-    let arch_name = llvm_target.split('-').next().expect("LLVM target must have a hyphen");
-    cmd.args(&["-arch", arch_name, "-isysroot", &sdk_root, "-Wl,-syslibroot", &sdk_root]);
+    if llvm_target.contains("macabi") {
+        cmd.args(&["-target", llvm_target])
+    } else {
+        let arch_name = llvm_target.split('-').next().expect("LLVM target must have a hyphen");
+        cmd.args(&["-arch", arch_name])
+    }
+    cmd.args(&["-isysroot", &sdk_root, "-Wl,-syslibroot", &sdk_root]);
 }
 
 fn get_apple_sdk_root(sdk_name: &str) -> Result<String, String> {
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index c84b87964b8..6aef5cb535a 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -282,6 +282,20 @@ pub struct TargetMachineFactoryConfig {
     pub split_dwarf_file: Option<PathBuf>,
 }
 
+impl TargetMachineFactoryConfig {
+    pub fn new(
+        cgcx: &CodegenContext<impl WriteBackendMethods>,
+        module_name: &str,
+    ) -> TargetMachineFactoryConfig {
+        let split_dwarf_file = if cgcx.target_can_use_split_dwarf {
+            cgcx.output_filenames.split_dwarf_filename(cgcx.split_debuginfo, Some(module_name))
+        } else {
+            None
+        };
+        TargetMachineFactoryConfig { split_dwarf_file }
+    }
+}
+
 pub type TargetMachineFactoryFn<B> = Arc<
     dyn Fn(TargetMachineFactoryConfig) -> Result<<B as WriteBackendMethods>::TargetMachine, String>
         + Send
@@ -311,10 +325,11 @@ pub struct CodegenContext<B: WriteBackendMethods> {
     pub tm_factory: TargetMachineFactoryFn<B>,
     pub msvc_imps_needed: bool,
     pub is_pe_coff: bool,
+    pub target_can_use_split_dwarf: bool,
     pub target_pointer_width: u32,
     pub target_arch: String,
     pub debuginfo: config::DebugInfo,
-    pub split_dwarf_kind: config::SplitDwarfKind,
+    pub split_debuginfo: rustc_target::spec::SplitDebuginfo,
 
     // Number of cgus excluding the allocator/metadata modules
     pub total_cgus: usize,
@@ -1035,10 +1050,11 @@ fn start_executing_work<B: ExtraBackendMethods>(
         total_cgus,
         msvc_imps_needed: msvc_imps_needed(tcx),
         is_pe_coff: tcx.sess.target.is_like_windows,
+        target_can_use_split_dwarf: tcx.sess.target_can_use_split_dwarf(),
         target_pointer_width: tcx.sess.target.pointer_width,
         target_arch: tcx.sess.target.arch.clone(),
         debuginfo: tcx.sess.opts.debuginfo,
-        split_dwarf_kind: tcx.sess.opts.debugging_opts.split_dwarf,
+        split_debuginfo: tcx.sess.split_debuginfo(),
     };
 
     // This is the "main loop" of parallel work happening for parallel codegen.
diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs
index 3a85c268e0e..b79a221a0e7 100644
--- a/compiler/rustc_codegen_ssa/src/mir/constant.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs
@@ -30,12 +30,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 .tcx()
                 .const_eval_resolve(ty::ParamEnv::reveal_all(), def, substs, promoted, None)
                 .map_err(|err| {
-                    if promoted.is_none() {
-                        self.cx
-                            .tcx()
-                            .sess
-                            .span_err(constant.span, "erroneous constant encountered");
-                    }
+                    self.cx.tcx().sess.span_err(constant.span, "erroneous constant encountered");
                     err
                 }),
             ty::ConstKind::Value(value) => Ok(value),
diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml
index 25c2851f6de..7413b0d9431 100644
--- a/compiler/rustc_expand/Cargo.toml
+++ b/compiler/rustc_expand/Cargo.toml
@@ -18,6 +18,7 @@ rustc_attr = { path = "../rustc_attr" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_feature = { path = "../rustc_feature" }
+rustc_lint_defs = { path = "../rustc_lint_defs" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_lexer = { path = "../rustc_lexer" }
 rustc_parse = { path = "../rustc_parse" }
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index e8c711cae64..73fbde70bda 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -11,12 +11,14 @@ use crate::mbe::transcribe::transcribe;
 use rustc_ast as ast;
 use rustc_ast::token::{self, NonterminalKind, NtTT, Token, TokenKind::*};
 use rustc_ast::tokenstream::{DelimSpan, TokenStream};
+use rustc_ast::NodeId;
 use rustc_ast_pretty::pprust;
 use rustc_attr::{self as attr, TransparencyError};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_feature::Features;
+use rustc_lint_defs::builtin::SEMICOLON_IN_EXPRESSIONS_FROM_MACROS;
 use rustc_parse::parser::Parser;
 use rustc_session::parse::ParseSess;
 use rustc_session::Session;
@@ -37,6 +39,7 @@ crate struct ParserAnyMacro<'a> {
     site_span: Span,
     /// The ident of the macro we're parsing
     macro_ident: Ident,
+    lint_node_id: NodeId,
     arm_span: Span,
 }
 
@@ -110,7 +113,8 @@ fn emit_frag_parse_err(
 
 impl<'a> ParserAnyMacro<'a> {
     crate fn make(mut self: Box<ParserAnyMacro<'a>>, kind: AstFragmentKind) -> AstFragment {
-        let ParserAnyMacro { site_span, macro_ident, ref mut parser, arm_span } = *self;
+        let ParserAnyMacro { site_span, macro_ident, ref mut parser, lint_node_id, arm_span } =
+            *self;
         let snapshot = &mut parser.clone();
         let fragment = match parse_ast_fragment(parser, kind) {
             Ok(f) => f,
@@ -124,6 +128,12 @@ impl<'a> ParserAnyMacro<'a> {
         // `macro_rules! m { () => { panic!(); } }` isn't parsed by `.parse_expr()`,
         // but `m!()` is allowed in expression positions (cf. issue #34706).
         if kind == AstFragmentKind::Expr && parser.token == token::Semi {
+            parser.sess.buffer_lint(
+                SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
+                parser.token.span,
+                lint_node_id,
+                "trailing semicolon in macro used in expression position",
+            );
             parser.bump();
         }
 
@@ -276,6 +286,7 @@ fn generic_extension<'cx>(
 
                 let mut p = Parser::new(sess, tts, false, None);
                 p.last_type_ascription = cx.current_expansion.prior_type_ascription;
+                let lint_node_id = cx.resolver.lint_node_id(cx.current_expansion.id);
 
                 // Let the context choose how to interpret the result.
                 // Weird, but useful for X-macros.
@@ -287,6 +298,7 @@ fn generic_extension<'cx>(
                     // macro leaves unparsed tokens.
                     site_span: sp,
                     macro_ident: name,
+                    lint_node_id,
                     arm_span,
                 });
             }
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 55d521a9b5f..305ae23669b 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -17,7 +17,7 @@ use rustc_span::edition::{Edition, DEFAULT_EDITION};
 use rustc_span::symbol::sym;
 use rustc_span::SourceFileHashAlgorithm;
 use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy};
-use rustc_target::spec::{RelocModel, RelroLevel, TlsModel};
+use rustc_target::spec::{RelocModel, RelroLevel, SplitDebuginfo, TlsModel};
 use std::collections::{BTreeMap, BTreeSet};
 use std::iter::FromIterator;
 use std::path::PathBuf;
@@ -446,6 +446,7 @@ fn test_codegen_options_tracking_hash() {
     tracked!(profile_use, Some(PathBuf::from("abc")));
     tracked!(relocation_model, Some(RelocModel::Pic));
     tracked!(soft_float, true);
+    tracked!(split_debuginfo, Some(SplitDebuginfo::Packed));
     tracked!(target_cpu, Some(String::from("abc")));
     tracked!(target_feature, String::from("all the features, all of them"));
 }
@@ -579,7 +580,6 @@ fn test_debugging_options_tracking_hash() {
     tracked!(relax_elf_relocations, Some(true));
     tracked!(relro_level, Some(RelroLevel::Full));
     tracked!(report_delayed_bugs, true);
-    tracked!(run_dsymutil, false);
     tracked!(sanitizer, SanitizerSet::ADDRESS);
     tracked!(sanitizer_memory_track_origins, 2);
     tracked!(sanitizer_recover, SanitizerSet::ADDRESS);
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index b1776599880..8bd9dad785c 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -746,6 +746,14 @@ impl<'tcx> LateContext<'tcx> {
             hir::QPath::Resolved(_, ref path) => path.res,
             hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
                 .maybe_typeck_results()
+                .filter(|typeck_results| typeck_results.hir_owner == id.owner)
+                .or_else(|| {
+                    if self.tcx.has_typeck_results(id.owner.to_def_id()) {
+                        Some(self.tcx.typeck(id.owner))
+                    } else {
+                        None
+                    }
+                })
                 .and_then(|typeck_results| typeck_results.type_dependent_def(id))
                 .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
         }
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index 015e1098711..3821a393efb 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -140,6 +140,8 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
     fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
         let generics = self.context.generics.take();
         self.context.generics = it.kind.generics();
+        let old_cached_typeck_results = self.context.cached_typeck_results.take();
+        let old_enclosing_body = self.context.enclosing_body.take();
         self.with_lint_attrs(it.hir_id, &it.attrs, |cx| {
             cx.with_param_env(it.hir_id, |cx| {
                 lint_callback!(cx, check_item, it);
@@ -147,6 +149,8 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
                 lint_callback!(cx, check_item_post, it);
             });
         });
+        self.context.enclosing_body = old_enclosing_body;
+        self.context.cached_typeck_results.set(old_cached_typeck_results);
         self.context.generics = generics;
     }
 
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 658372ac336..a8bf1ce51bb 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -1,3 +1,4 @@
+// ignore-tidy-filelength
 //! Some lints that are built in to the compiler.
 //!
 //! These are the built-in lints that are emitted direct in the main
@@ -2833,6 +2834,52 @@ declare_lint! {
     "detects `#[unstable]` on stable trait implementations for stable types"
 }
 
+declare_lint! {
+    /// The `semicolon_in_expressions_from_macros` lint detects trailing semicolons
+    /// in macro bodies when the macro is invoked in expression position.
+    /// This was previous accepted, but is being phased out.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(semicolon_in_expressions_from_macros)]
+    /// macro_rules! foo {
+    ///     () => { true; }
+    /// }
+    ///
+    /// fn main() {
+    ///     let val = match true {
+    ///         true => false,
+    ///         _ => foo!()
+    ///     };
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Previous, Rust ignored trailing semicolon in a macro
+    /// body when a macro was invoked in expression position.
+    /// However, this makes the treatment of semicolons in the language
+    /// inconsistent, and could lead to unexpected runtime behavior
+    /// in some circumstances (e.g. if the macro author expects
+    /// a value to be dropped).
+    ///
+    /// This is a [future-incompatible] lint to transition this
+    /// to a hard error in the future. See [issue #79813] for more details.
+    ///
+    /// [issue #79813]: https://github.com/rust-lang/rust/issues/79813
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
+    pub SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
+    Allow,
+    "trailing semicolon in macro body used as expression",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #79813 <https://github.com/rust-lang/rust/issues/79813>",
+        edition: None,
+    };
+}
+
 declare_lint_pass! {
     /// Does nothing as a lint pass, but registers some `Lint`s
     /// that are used by other parts of the compiler.
@@ -2920,6 +2967,7 @@ declare_lint_pass! {
         USELESS_DEPRECATED,
         UNSUPPORTED_NAKED_FUNCTIONS,
         MISSING_ABI,
+        SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
     ]
 }
 
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
index e1af6fc07cf..73196c732f5 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
@@ -1,9 +1,12 @@
 use rustc_hir as hir;
 use rustc_hir::Node;
 use rustc_index::vec::Idx;
-use rustc_middle::mir::{self, ClearCrossCrate, Local, LocalDecl, LocalInfo, Location};
 use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
 use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::{
+    hir::place::PlaceBase,
+    mir::{self, ClearCrossCrate, Local, LocalDecl, LocalInfo, Location},
+};
 use rustc_span::source_map::DesugaringKind;
 use rustc_span::symbol::{kw, Symbol};
 use rustc_span::Span;
@@ -241,6 +244,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     format!("mut {}", self.local_names[local].unwrap()),
                     Applicability::MachineApplicable,
                 );
+                let tcx = self.infcx.tcx;
+                if let ty::Closure(id, _) = the_place_err.ty(self.body, tcx).ty.kind() {
+                    self.show_mutating_upvar(tcx, id, the_place_err, &mut err);
+                }
             }
 
             // Also suggest adding mut for upvars
@@ -271,6 +278,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                         );
                     }
                 }
+
+                let tcx = self.infcx.tcx;
+                if let ty::Ref(_, ty, Mutability::Mut) = the_place_err.ty(self.body, tcx).ty.kind()
+                {
+                    if let ty::Closure(id, _) = ty.kind() {
+                        self.show_mutating_upvar(tcx, id, the_place_err, &mut err);
+                    }
+                }
             }
 
             // complete hack to approximate old AST-borrowck
@@ -463,6 +478,45 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         err.buffer(&mut self.errors_buffer);
     }
 
+    // point to span of upvar making closure call require mutable borrow
+    fn show_mutating_upvar(
+        &self,
+        tcx: TyCtxt<'_>,
+        id: &hir::def_id::DefId,
+        the_place_err: PlaceRef<'tcx>,
+        err: &mut DiagnosticBuilder<'_>,
+    ) {
+        let id = id.expect_local();
+        let tables = tcx.typeck(id);
+        let hir_id = tcx.hir().local_def_id_to_hir_id(id);
+        let (span, place) = &tables.closure_kind_origins()[hir_id];
+        let reason = if let PlaceBase::Upvar(upvar_id) = place.base {
+            let upvar = ty::place_to_string_for_capture(tcx, place);
+            match tables.upvar_capture(upvar_id) {
+                ty::UpvarCapture::ByRef(ty::UpvarBorrow {
+                    kind: ty::BorrowKind::MutBorrow,
+                    ..
+                }) => {
+                    format!("mutable borrow of `{}`", upvar)
+                }
+                ty::UpvarCapture::ByValue(_) => {
+                    format!("possible mutation of `{}`", upvar)
+                }
+                _ => bug!("upvar `{}` borrowed, but not mutably", upvar),
+            }
+        } else {
+            bug!("not an upvar")
+        };
+        err.span_label(
+            *span,
+            format!(
+                "calling `{}` requires mutable binding due to {}",
+                self.describe_place(the_place_err).unwrap(),
+                reason
+            ),
+        );
+    }
+
     /// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected.
     fn expected_fn_found_fn_mut_call(&self, err: &mut DiagnosticBuilder<'_>, sp: Span, act: &str) {
         err.span_label(sp, format!("cannot {}", act));
diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs
index df163f65628..252f5e7ef2f 100644
--- a/compiler/rustc_mir/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs
@@ -298,6 +298,8 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
         tcx.def_span(def.did),
         key.param_env,
         CompileTimeInterpreter::new(tcx.sess.const_eval_limit()),
+        // Statics (and promoteds inside statics) may access other statics, because unlike consts
+        // they do not have to behave "as if" they were evaluated at runtime.
         MemoryExtra { can_access_statics: is_static },
     );
 
@@ -305,83 +307,35 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
     match res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body)) {
         Err(error) => {
             let err = ConstEvalErr::new(&ecx, error, None);
-            // errors in statics are always emitted as fatal errors
-            if is_static {
-                // Ensure that if the above error was either `TooGeneric` or `Reported`
-                // an error must be reported.
-                let v = err.report_as_error(
-                    ecx.tcx.at(ecx.cur_span()),
-                    "could not evaluate static initializer",
-                );
-
-                // If this is `Reveal:All`, then we need to make sure an error is reported but if
-                // this is `Reveal::UserFacing`, then it's expected that we could get a
-                // `TooGeneric` error. When we fall back to `Reveal::All`, then it will either
-                // succeed or we'll report this error then.
-                if key.param_env.reveal() == Reveal::All {
-                    tcx.sess.delay_span_bug(
-                        err.span,
-                        &format!("static eval failure did not emit an error: {:#?}", v),
-                    );
-                }
-
-                Err(v)
-            } else if let Some(def) = def.as_local() {
-                // constant defined in this crate, we can figure out a lint level!
-                match tcx.def_kind(def.did.to_def_id()) {
-                    // constants never produce a hard error at the definition site. Anything else is
-                    // a backwards compatibility hazard (and will break old versions of winapi for
-                    // sure)
-                    //
-                    // note that validation may still cause a hard error on this very same constant,
-                    // because any code that existed before validation could not have failed
-                    // validation thus preventing such a hard error from being a backwards
-                    // compatibility hazard
-                    DefKind::Const | DefKind::AssocConst => {
-                        let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
-                        Err(err.report_as_lint(
-                            tcx.at(tcx.def_span(def.did)),
-                            "any use of this value will cause an error",
-                            hir_id,
-                            Some(err.span),
-                        ))
-                    }
-                    // promoting runtime code is only allowed to error if it references broken
-                    // constants any other kind of error will be reported to the user as a
-                    // deny-by-default lint
-                    _ => {
-                        if let Some(p) = cid.promoted {
-                            let span = tcx.promoted_mir_opt_const_arg(def.to_global())[p].span;
-                            if let err_inval!(ReferencedConstant) = err.error {
-                                Err(err.report_as_error(
-                                    tcx.at(span),
-                                    "evaluation of constant expression failed",
-                                ))
-                            } else {
-                                Err(err.report_as_lint(
-                                    tcx.at(span),
-                                    "reaching this expression at runtime will panic or abort",
-                                    tcx.hir().local_def_id_to_hir_id(def.did),
-                                    Some(err.span),
-                                ))
-                            }
-                        // anything else (array lengths, enum initializers, constant patterns) are
-                        // reported as hard errors
-                        } else {
-                            Err(err.report_as_error(
-                                ecx.tcx.at(ecx.cur_span()),
-                                "evaluation of constant value failed",
-                            ))
-                        }
-                    }
-                }
+            // Some CTFE errors raise just a lint, not a hard error; see
+            // <https://github.com/rust-lang/rust/issues/71800>.
+            let emit_as_lint = if let Some(def) = def.as_local() {
+                // (Associated) consts only emit a lint, since they might be unused.
+                matches!(tcx.def_kind(def.did.to_def_id()), DefKind::Const | DefKind::AssocConst)
             } else {
-                // use of broken constant from other crate
-                Err(err.report_as_error(ecx.tcx.at(ecx.cur_span()), "could not evaluate constant"))
+                // use of broken constant from other crate: always an error
+                false
+            };
+            if emit_as_lint {
+                let hir_id = tcx.hir().local_def_id_to_hir_id(def.as_local().unwrap().did);
+                Err(err.report_as_lint(
+                    tcx.at(tcx.def_span(def.did)),
+                    "any use of this value will cause an error",
+                    hir_id,
+                    Some(err.span),
+                ))
+            } else {
+                let msg = if is_static {
+                    "could not evaluate static initializer"
+                } else {
+                    "evaluation of constant value failed"
+                };
+                Err(err.report_as_error(ecx.tcx.at(ecx.cur_span()), msg))
             }
         }
         Ok(mplace) => {
-            // Since evaluation had no errors, valiate the resulting constant:
+            // Since evaluation had no errors, validate the resulting constant.
+            // This is a separate `try` block to provide more targeted error reporting.
             let validation = try {
                 let mut ref_tracking = RefTracking::new(mplace);
                 let mut inner = false;
@@ -399,7 +353,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
                 }
             };
             if let Err(error) = validation {
-                // Validation failed, report an error
+                // Validation failed, report an error. This is always a hard error.
                 let err = ConstEvalErr::new(&ecx, error, None);
                 Err(err.struct_error(
                     ecx.tcx,
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 5d6120cd310..d0adee2429d 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -344,6 +344,8 @@ impl<'a> ResolverExpand for Resolver<'a> {
     }
 
     fn lint_node_id(&mut self, expn_id: ExpnId) -> NodeId {
+        // FIXME - make this more precise. This currently returns the NodeId of the
+        // nearest closing item - we should try to return the closest parent of the ExpnId
         self.invocation_parents
             .get(&expn_id)
             .map_or(ast::CRATE_NODE_ID, |id| self.def_id_to_node_id[*id])
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 6e269e9e126..f9e40919149 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -13,7 +13,7 @@ use rustc_data_structures::impl_stable_hash_via_hash;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 
 use rustc_target::abi::{Align, TargetDataLayout};
-use rustc_target::spec::{Target, TargetTriple};
+use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple};
 
 use crate::parse::CrateConfig;
 use rustc_feature::UnstableFeatures;
@@ -221,23 +221,6 @@ pub enum DebugInfo {
     Full,
 }
 
-/// Some debuginfo requires link-time relocation and some does not. LLVM can partition the debuginfo
-/// into sections depending on whether or not it requires link-time relocation. Split DWARF
-/// provides a mechanism which allows the linker to skip the sections which don't require link-time
-/// relocation - either by putting those sections into DWARF object files, or keeping them in the
-/// object file in such a way that the linker will skip them.
-#[derive(Clone, Copy, Debug, PartialEq, Hash)]
-pub enum SplitDwarfKind {
-    /// Disabled.
-    None,
-    /// Sections which do not require relocation are written into the object file but ignored
-    /// by the linker.
-    Single,
-    /// Sections which do not require relocation are written into a DWARF object (`.dwo`) file,
-    /// which is skipped by the linker by virtue of being a different file.
-    Split,
-}
-
 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
 #[derive(Encodable, Decodable)]
 pub enum OutputType {
@@ -635,10 +618,10 @@ impl OutputFilenames {
     /// mode is being used, which is the logic that this function is intended to encapsulate.
     pub fn split_dwarf_filename(
         &self,
-        split_dwarf_kind: SplitDwarfKind,
+        split_debuginfo_kind: SplitDebuginfo,
         cgu_name: Option<&str>,
     ) -> Option<PathBuf> {
-        self.split_dwarf_path(split_dwarf_kind, cgu_name)
+        self.split_dwarf_path(split_debuginfo_kind, cgu_name)
             .map(|path| path.strip_prefix(&self.out_directory).unwrap_or(&path).to_path_buf())
     }
 
@@ -646,19 +629,19 @@ impl OutputFilenames {
     /// mode is being used, which is the logic that this function is intended to encapsulate.
     pub fn split_dwarf_path(
         &self,
-        split_dwarf_kind: SplitDwarfKind,
+        split_debuginfo_kind: SplitDebuginfo,
         cgu_name: Option<&str>,
     ) -> Option<PathBuf> {
         let obj_out = self.temp_path(OutputType::Object, cgu_name);
         let dwo_out = self.temp_path_dwo(cgu_name);
-        match split_dwarf_kind {
-            SplitDwarfKind::None => None,
+        match split_debuginfo_kind {
+            SplitDebuginfo::Off => None,
             // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
             // (pointing at the path which is being determined here). Use the path to the current
             // object file.
-            SplitDwarfKind::Single => Some(obj_out),
+            SplitDebuginfo::Packed => Some(obj_out),
             // Split mode emits the DWARF into a different file, use that path.
-            SplitDwarfKind::Split => Some(dwo_out),
+            SplitDebuginfo::Unpacked => Some(dwo_out),
         }
     }
 }
@@ -1910,6 +1893,15 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
 
     let pretty = parse_pretty(matches, &debugging_opts, error_format);
 
+    if !debugging_opts.unstable_options
+        && !target_triple.triple().contains("apple")
+        && cg.split_debuginfo.is_some()
+    {
+        {
+            early_error(error_format, "`-Csplit-debuginfo` is unstable on this platform");
+        }
+    }
+
     Options {
         crate_types,
         optimize: opt_level,
@@ -2191,7 +2183,7 @@ crate mod dep_tracking {
     use rustc_feature::UnstableFeatures;
     use rustc_span::edition::Edition;
     use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
-    use rustc_target::spec::{RelroLevel, TargetTriple, TlsModel};
+    use rustc_target::spec::{RelroLevel, SplitDebuginfo, TargetTriple, TlsModel};
     use std::collections::hash_map::DefaultHasher;
     use std::collections::BTreeMap;
     use std::hash::Hash;
@@ -2263,6 +2255,7 @@ crate mod dep_tracking {
     impl_dep_tracking_hash_via_hash!(TargetTriple);
     impl_dep_tracking_hash_via_hash!(Edition);
     impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
+    impl_dep_tracking_hash_via_hash!(Option<SplitDebuginfo>);
     impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
     impl_dep_tracking_hash_via_hash!(Option<SymbolManglingVersion>);
     impl_dep_tracking_hash_via_hash!(Option<SourceFileHashAlgorithm>);
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 30af65e49a0..2aaab84585d 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -6,7 +6,7 @@ use crate::search_paths::SearchPath;
 use crate::utils::NativeLibKind;
 
 use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy};
-use rustc_target::spec::{RelocModel, RelroLevel, TargetTriple, TlsModel};
+use rustc_target::spec::{RelocModel, RelroLevel, SplitDebuginfo, TargetTriple, TlsModel};
 
 use rustc_feature::UnstableFeatures;
 use rustc_span::edition::Edition;
@@ -269,7 +269,6 @@ macro_rules! options {
         pub const parse_switch_with_opt_path: &str =
             "an optional path to the profiling data output directory";
         pub const parse_merge_functions: &str = "one of: `disabled`, `trampolines`, or `aliases`";
-        pub const parse_split_dwarf_kind: &str = "one of: `none`, `single` or `split`";
         pub const parse_symbol_mangling_version: &str = "either `legacy` or `v0` (RFC 2603)";
         pub const parse_src_file_hash: &str = "either `md5` or `sha1`";
         pub const parse_relocation_model: &str =
@@ -280,6 +279,8 @@ macro_rules! options {
             "one of supported TLS models (`rustc --print tls-models`)";
         pub const parse_target_feature: &str = parse_string;
         pub const parse_wasi_exec_model: &str = "either `command` or `reactor`";
+        pub const parse_split_debuginfo: &str =
+            "one of supported split-debuginfo modes (`off` or `dsymutil`)";
     }
 
     #[allow(dead_code)]
@@ -678,19 +679,6 @@ macro_rules! options {
             true
         }
 
-        fn parse_split_dwarf_kind(
-            slot: &mut SplitDwarfKind,
-            v: Option<&str>,
-        ) -> bool {
-            *slot = match v {
-                Some("none") => SplitDwarfKind::None,
-                Some("split") => SplitDwarfKind::Split,
-                Some("single") => SplitDwarfKind::Single,
-                _ => return false,
-            };
-            true
-        }
-
         fn parse_symbol_mangling_version(
             slot: &mut Option<SymbolManglingVersion>,
             v: Option<&str>,
@@ -732,6 +720,14 @@ macro_rules! options {
             }
             true
         }
+
+        fn parse_split_debuginfo(slot: &mut Option<SplitDebuginfo>, v: Option<&str>) -> bool {
+            match v.and_then(|s| SplitDebuginfo::from_str(s).ok()) {
+                Some(e) => *slot = Some(e),
+                _ => return false,
+            }
+            true
+        }
     }
 ) }
 
@@ -830,6 +826,8 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
         "save all temporary output files during compilation (default: no)"),
     soft_float: bool = (false, parse_bool, [TRACKED],
         "use soft float ABI (*eabihf targets only) (default: no)"),
+    split_debuginfo: Option<SplitDebuginfo> = (None, parse_split_debuginfo, [TRACKED],
+        "how to handle split-debuginfo, a platform-specific option"),
     target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
         "select target processor (`rustc --print target-cpus` for details)"),
     target_feature: String = (String::new(), parse_target_feature, [TRACKED],
@@ -1073,11 +1071,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
         "choose which RELRO level to use"),
     report_delayed_bugs: bool = (false, parse_bool, [TRACKED],
         "immediately print bugs registered with `delay_span_bug` (default: no)"),
-    // The default historical behavior was to always run dsymutil, so we're
-    // preserving that temporarily, but we're likely to switch the default
-    // soon.
-    run_dsymutil: bool = (true, parse_bool, [TRACKED],
-        "if on Mac, run `dsymutil` and delete intermediate object files (default: yes)"),
     sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
         "use a sanitizer"),
     sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED],
@@ -1112,8 +1105,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
         "hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"),
     strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
         "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"),
-    split_dwarf: SplitDwarfKind = (SplitDwarfKind::None, parse_split_dwarf_kind, [UNTRACKED],
-        "enable generation of split dwarf"),
     split_dwarf_inlining: bool = (true, parse_bool, [UNTRACKED],
         "provide minimal debug info in the object/executable to facilitate online \
          symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF"),
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 6d018542286..dad21e59502 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -28,7 +28,7 @@ use rustc_span::source_map::{FileLoader, MultiSpan, RealFileLoader, SourceMap, S
 use rustc_span::{sym, SourceFileHashAlgorithm, Symbol};
 use rustc_target::asm::InlineAsmArch;
 use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel};
-use rustc_target::spec::{Target, TargetTriple, TlsModel};
+use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple, TlsModel};
 
 use std::cell::{self, RefCell};
 use std::env;
@@ -804,6 +804,14 @@ impl Session {
             )
     }
 
+    pub fn split_debuginfo(&self) -> SplitDebuginfo {
+        self.opts.cg.split_debuginfo.unwrap_or(self.target.split_debuginfo)
+    }
+
+    pub fn target_can_use_split_dwarf(&self) -> bool {
+        !self.target.is_like_windows && !self.target.is_like_osx
+    }
+
     pub fn must_not_eliminate_frame_pointers(&self) -> bool {
         // "mcount" function relies on stack pointer.
         // See <https://sourceware.org/binutils/docs/gprof/Implementation.html>.
diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs
index 88422395216..3b458962b3d 100644
--- a/compiler/rustc_target/src/spec/apple_base.rs
+++ b/compiler/rustc_target/src/spec/apple_base.rs
@@ -1,6 +1,6 @@
 use std::env;
 
-use crate::spec::{LinkArgs, TargetOptions};
+use crate::spec::{LinkArgs, SplitDebuginfo, TargetOptions};
 
 pub fn opts(os: &str) -> TargetOptions {
     // ELF TLS is only available in macOS 10.7+. If you try to compile for 10.6
@@ -36,6 +36,10 @@ pub fn opts(os: &str) -> TargetOptions {
         emit_debug_gdb_scripts: false,
         eh_frame_header: false,
 
+        // The historical default for macOS targets is to run `dsymutil` which
+        // generates a packed version of debuginfo split from the main file.
+        split_debuginfo: SplitDebuginfo::Packed,
+
         // This environment variable is pretty magical but is intended for
         // producing deterministic builds. This was first discovered to be used
         // by the `ar` tool as a way to control whether or not mtime entries in
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 90d35efaa25..0227febd294 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -448,6 +448,69 @@ impl fmt::Display for LinkOutputKind {
 
 pub type LinkArgs = BTreeMap<LinkerFlavor, Vec<String>>;
 
+#[derive(Clone, Copy, Hash, Debug, PartialEq, Eq)]
+pub enum SplitDebuginfo {
+    /// Split debug-information is disabled, meaning that on supported platforms
+    /// you can find all debug information in the executable itself. This is
+    /// only supported for ELF effectively.
+    ///
+    /// * Windows - not supported
+    /// * macOS - don't run `dsymutil`
+    /// * ELF - `.dwarf_*` sections
+    Off,
+
+    /// Split debug-information can be found in a "packed" location separate
+    /// from the final artifact. This is supported on all platforms.
+    ///
+    /// * Windows - `*.pdb`
+    /// * macOS - `*.dSYM` (run `dsymutil`)
+    /// * ELF - `*.dwp` (run `rust-llvm-dwp`)
+    Packed,
+
+    /// Split debug-information can be found in individual object files on the
+    /// filesystem. The main executable may point to the object files.
+    ///
+    /// * Windows - not supported
+    /// * macOS - supported, scattered object files
+    /// * ELF - supported, scattered `*.dwo` files
+    Unpacked,
+}
+
+impl SplitDebuginfo {
+    fn as_str(&self) -> &'static str {
+        match self {
+            SplitDebuginfo::Off => "off",
+            SplitDebuginfo::Packed => "packed",
+            SplitDebuginfo::Unpacked => "unpacked",
+        }
+    }
+}
+
+impl FromStr for SplitDebuginfo {
+    type Err = ();
+
+    fn from_str(s: &str) -> Result<SplitDebuginfo, ()> {
+        Ok(match s {
+            "off" => SplitDebuginfo::Off,
+            "unpacked" => SplitDebuginfo::Unpacked,
+            "packed" => SplitDebuginfo::Packed,
+            _ => return Err(()),
+        })
+    }
+}
+
+impl ToJson for SplitDebuginfo {
+    fn to_json(&self) -> Json {
+        self.as_str().to_json()
+    }
+}
+
+impl fmt::Display for SplitDebuginfo {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str(self.as_str())
+    }
+}
+
 macro_rules! supported_targets {
     ( $(($( $triple:literal, )+ $module:ident ),)+ ) => {
         $(mod $module;)+
@@ -1085,6 +1148,10 @@ pub struct TargetOptions {
     /// Is true if the target is an ARM architecture using thumb v1 which allows for
     /// thumb and arm interworking.
     pub has_thumb_interworking: bool,
+
+    /// How to handle split debug information, if at all. Specifying `None` has
+    /// target-specific meaning.
+    pub split_debuginfo: SplitDebuginfo,
 }
 
 impl Default for TargetOptions {
@@ -1184,6 +1251,7 @@ impl Default for TargetOptions {
             use_ctors_section: false,
             eh_frame_header: true,
             has_thumb_interworking: false,
+            split_debuginfo: SplitDebuginfo::Off,
         }
     }
 }
@@ -1382,6 +1450,18 @@ impl Target {
                     Some(Ok(()))
                 })).unwrap_or(Ok(()))
             } );
+            ($key_name:ident, SplitDebuginfo) => ( {
+                let name = (stringify!($key_name)).replace("_", "-");
+                obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                    match s.parse::<SplitDebuginfo>() {
+                        Ok(level) => base.$key_name = level,
+                        _ => return Some(Err(format!("'{}' is not a valid value for \
+                                                      split-debuginfo. Use 'off' or 'dsymutil'.",
+                                                      s))),
+                    }
+                    Some(Ok(()))
+                })).unwrap_or(Ok(()))
+            } );
             ($key_name:ident, list) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
                 if let Some(v) = obj.find(&name).and_then(Json::as_array) {
@@ -1627,6 +1707,7 @@ impl Target {
         key!(use_ctors_section, bool);
         key!(eh_frame_header, bool);
         key!(has_thumb_interworking, bool);
+        key!(split_debuginfo, SplitDebuginfo)?;
 
         // NB: The old name is deprecated, but support for it is retained for
         // compatibility.
@@ -1862,6 +1943,7 @@ impl ToJson for Target {
         target_option_val!(use_ctors_section);
         target_option_val!(eh_frame_header);
         target_option_val!(has_thumb_interworking);
+        target_option_val!(split_debuginfo);
 
         if default.unsupported_abis != self.unsupported_abis {
             d.insert(
diff --git a/compiler/rustc_target/src/spec/msvc_base.rs b/compiler/rustc_target/src/spec/msvc_base.rs
index 8cd6735a8c1..39c0d5f0bb4 100644
--- a/compiler/rustc_target/src/spec/msvc_base.rs
+++ b/compiler/rustc_target/src/spec/msvc_base.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, TargetOptions};
+use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, SplitDebuginfo, TargetOptions};
 
 pub fn opts() -> TargetOptions {
     let pre_link_args_msvc = vec![
@@ -27,6 +27,10 @@ pub fn opts() -> TargetOptions {
         abi_return_struct_as_int: true,
         emit_debug_gdb_scripts: false,
 
+        // Currently this is the only supported method of debuginfo on MSVC
+        // where `*.pdb` files show up next to the final artifact.
+        split_debuginfo: SplitDebuginfo::Packed,
+
         ..Default::default()
     }
 }
diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs
index 29e191db0f6..081f282edcf 100644
--- a/library/core/src/iter/adapters/flatten.rs
+++ b/library/core/src/iter/adapters/flatten.rs
@@ -265,7 +265,13 @@ where
                 }
             }
             match self.iter.next() {
-                None => return self.backiter.as_mut()?.next(),
+                None => match self.backiter.as_mut()?.next() {
+                    None => {
+                        self.backiter = None;
+                        return None;
+                    }
+                    elt @ Some(_) => return elt,
+                },
                 Some(inner) => self.frontiter = Some(inner.into_iter()),
             }
         }
@@ -353,7 +359,13 @@ where
                 }
             }
             match self.iter.next_back() {
-                None => return self.frontiter.as_mut()?.next_back(),
+                None => match self.frontiter.as_mut()?.next_back() {
+                    None => {
+                        self.frontiter = None;
+                        return None;
+                    }
+                    elt @ Some(_) => return elt,
+                },
                 next => self.backiter = next.map(IntoIterator::into_iter),
             }
         }
diff --git a/library/core/tests/iter/adapters/flatten.rs b/library/core/tests/iter/adapters/flatten.rs
index bd2c6fd9252..4bbae6947bf 100644
--- a/library/core/tests/iter/adapters/flatten.rs
+++ b/library/core/tests/iter/adapters/flatten.rs
@@ -64,6 +64,14 @@ fn test_flatten_non_fused_outer() {
     assert_eq!(iter.next_back(), Some(1));
     assert_eq!(iter.next(), Some(0));
     assert_eq!(iter.next(), None);
+    assert_eq!(iter.next(), None);
+
+    let mut iter = NonFused::new(once(0..2)).flatten();
+
+    assert_eq!(iter.next(), Some(0));
+    assert_eq!(iter.next_back(), Some(1));
+    assert_eq!(iter.next_back(), None);
+    assert_eq!(iter.next_back(), None);
 }
 
 #[test]
@@ -74,6 +82,15 @@ fn test_flatten_non_fused_inner() {
     assert_eq!(iter.next(), Some(0));
     assert_eq!(iter.next(), Some(1));
     assert_eq!(iter.next(), None);
+    assert_eq!(iter.next(), None);
+
+    let mut iter = once(0..1).chain(once(1..3)).flat_map(NonFused::new);
+
+    assert_eq!(iter.next(), Some(0));
+    assert_eq!(iter.next_back(), Some(2));
+    assert_eq!(iter.next_back(), Some(1));
+    assert_eq!(iter.next_back(), None);
+    assert_eq!(iter.next_back(), None);
 }
 
 #[test]
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 5350c9eefe7..8576f57959a 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -833,6 +833,7 @@ class RustBuild(object):
         target_linker = self.get_toml("linker", build_section)
         if target_linker is not None:
             env["RUSTFLAGS"] += " -C linker=" + target_linker
+        # cfg(bootstrap): Add `-Wsemicolon_in_expressions_from_macros` after the next beta bump
         env["RUSTFLAGS"] += " -Wrust_2018_idioms -Wunused_lifetimes"
         if self.get_toml("deny-warnings", "rust") != "false":
             env["RUSTFLAGS"] += " -Dwarnings"
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 62065e27dd9..f1a160250db 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -1139,10 +1139,18 @@ impl<'a> Builder<'a> {
         // itself, we skip it by default since we know it's safe to do so in that case.
         // See https://github.com/rust-lang/rust/issues/79361 for more info on this flag.
         if target.contains("apple") {
-            if self.config.rust_run_dsymutil {
-                rustflags.arg("-Zrun-dsymutil=yes");
+            if stage == 0 {
+                if self.config.rust_run_dsymutil {
+                    rustflags.arg("-Zrun-dsymutil=yes");
+                } else {
+                    rustflags.arg("-Zrun-dsymutil=no");
+                }
             } else {
-                rustflags.arg("-Zrun-dsymutil=no");
+                if self.config.rust_run_dsymutil {
+                    rustflags.arg("-Csplit-debuginfo=packed");
+                } else {
+                    rustflags.arg("-Csplit-debuginfo=unpacked");
+                }
             }
         }
 
@@ -1250,6 +1258,12 @@ impl<'a> Builder<'a> {
             // some code doesn't go through this `rustc` wrapper.
             lint_flags.push("-Wrust_2018_idioms");
             lint_flags.push("-Wunused_lifetimes");
+            // cfg(bootstrap): unconditionally enable this warning after the next beta bump
+            // This is currently disabled for the stage1 libstd, since build scripts
+            // will end up using the bootstrap compiler (which doesn't yet support this lint)
+            if compiler.stage != 0 && mode != Mode::Std {
+                lint_flags.push("-Wsemicolon_in_expressions_from_macros");
+            }
 
             if self.config.deny_warnings {
                 lint_flags.push("-Dwarnings");
diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md
index f6493e49c3c..51e7d987d9d 100644
--- a/src/doc/rustc/src/codegen-options/index.md
+++ b/src/doc/rustc/src/codegen-options/index.md
@@ -492,6 +492,34 @@ point instructions in software. It takes one of the following values:
 * `y`, `yes`, `on`, or no value: use soft floats.
 * `n`, `no`, or `off`: use hardware floats (the default).
 
+## split-debuginfo
+
+This option controls the emission of "split debuginfo" for debug information
+that `rustc` generates. The default behavior of this option is
+platform-specific, and not all possible values for this option work on all
+platform. Possible values are:
+
+* `off` - This is the default for platforms with ELF binaries and windows-gnu
+  (not Windows MSVC and not macOS). This typically means that dwarf debug
+  information can be found in the final artifact in sections of the executable.
+  This option is not supported on Windows MSVC. On macOS this options prevents
+  the final execution of `dsymutil` to generate debuginfo.
+
+* `packed` - This is the default for Windows MSVC and macOS platforms. The term
+  "packed" here means that all the debug information is packed into a separate
+  file from the main executable. On Windows MSVC this is a `*.pdb` file, on
+  macOS this is a `*.dSYM` folder, and on other platforms this is a `*.dwp`
+  files.
+
+* `unpacked` - This means that debug information will be found in separate
+  files for each compilation unit (object file). This is not supported on
+  Windows MSVC. On macOS this means the original object files will contain
+  debug information. On other Unix platforms this means that `*.dwo` files will
+  contain debug information.
+
+Note that `packed` and `unpacked` gated behind `-Zunstable-options` on
+non-macOS platforms at this time.
+
 ## target-cpu
 
 This instructs `rustc` to generate code specifically for a particular processor.
@@ -499,7 +527,7 @@ This instructs `rustc` to generate code specifically for a particular processor.
 You can run `rustc --print target-cpus` to see the valid options to pass
 here. Each target has a default base CPU. Special values include:
 
-* `native` can be passed to use the processor of the host machine. 
+* `native` can be passed to use the processor of the host machine.
 * `generic` refers to an LLVM target with minimal features but modern tuning.
 
 ## target-feature
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index b0f5bac6abd..db64b31f31c 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -17,6 +17,7 @@ smallvec = "1.0"
 tempfile = "3"
 itertools = "0.9"
 regex = "1"
+rustdoc-json-types = { path = "../rustdoc-json-types" }
 
 [dev-dependencies]
 expect-test = "1.0"
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 01915c33a07..74b61f1555c 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -659,6 +659,8 @@ fn fmt_type(
     use_absolute: bool,
     cache: &Cache,
 ) -> fmt::Result {
+    debug!("fmt_type(t = {:?})", t);
+
     match *t {
         clean::Generic(name) => write!(f, "{}", name),
         clean::ResolvedPath { did, ref param_names, ref path, is_generic } => {
@@ -675,21 +677,22 @@ fn fmt_type(
             if f.alternate() {
                 write!(
                     f,
-                    "{}{:#}fn{:#}{:#}",
+                    "{:#}{}{:#}fn{:#}",
+                    decl.print_hrtb_with_space(cache),
                     decl.unsafety.print_with_space(),
                     print_abi_with_space(decl.abi),
-                    decl.print_generic_params(cache),
                     decl.decl.print(cache)
                 )
             } else {
                 write!(
                     f,
-                    "{}{}",
+                    "{}{}{}",
+                    decl.print_hrtb_with_space(cache),
                     decl.unsafety.print_with_space(),
                     print_abi_with_space(decl.abi)
                 )?;
                 primitive_link(f, PrimitiveType::Fn, "fn", cache)?;
-                write!(f, "{}{}", decl.print_generic_params(cache), decl.decl.print(cache))
+                write!(f, "{}", decl.decl.print(cache))
             }
         }
         clean::Tuple(ref typs) => {
@@ -992,8 +995,14 @@ impl clean::FnRetTy {
 }
 
 impl clean::BareFunctionDecl {
-    fn print_generic_params<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
-        comma_sep(self.generic_params.iter().map(move |g| g.print(cache)))
+    fn print_hrtb_with_space<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
+        display_fn(move |f| {
+            if !self.generic_params.is_empty() {
+                write!(f, "for<{}> ", comma_sep(self.generic_params.iter().map(|g| g.print(cache))))
+            } else {
+                Ok(())
+            }
+        })
     }
 }
 
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index bb9a7be590e..df3701487d7 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1345,6 +1345,7 @@ impl AllTypes {
         write!(
             f,
             "<h1 class=\"fqn\">\
+                 <span class=\"in-band\">List of all items</span>\
                  <span class=\"out-of-band\">\
                      <span id=\"render-detail\">\
                          <a id=\"toggle-all-docs\" href=\"javascript:void(0)\" \
@@ -1353,7 +1354,6 @@ impl AllTypes {
                          </a>\
                      </span>
                  </span>
-                 <span class=\"in-band\">List of all items</span>\
              </h1>"
         );
         print_entries(f, &self.structs, "Structs", "structs");
@@ -1711,36 +1711,7 @@ where
 fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer) {
     debug_assert!(!item.is_stripped());
     // Write the breadcrumb trail header for the top
-    write!(buf, "<h1 class=\"fqn\"><span class=\"out-of-band\">");
-    render_stability_since_raw(
-        buf,
-        item.stable_since(cx.tcx()).as_deref(),
-        item.const_stable_since(cx.tcx()).as_deref(),
-        None,
-        None,
-    );
-    write!(
-        buf,
-        "<span id=\"render-detail\">\
-                <a id=\"toggle-all-docs\" href=\"javascript:void(0)\" \
-                    title=\"collapse all docs\">\
-                    [<span class=\"inner\">&#x2212;</span>]\
-                </a>\
-            </span>"
-    );
-
-    // Write `src` tag
-    //
-    // When this item is part of a `crate use` in a downstream crate, the
-    // [src] link in the downstream documentation will actually come back to
-    // this page, and this link will be auto-clicked. The `id` attribute is
-    // used to find the link to auto-click.
-    if cx.shared.include_sources && !item.is_primitive() {
-        write_srclink(cx, item, buf);
-    }
-
-    write!(buf, "</span>"); // out-of-band
-    write!(buf, "<span class=\"in-band\">");
+    write!(buf, "<h1 class=\"fqn\"><span class=\"in-band\">");
     let name = match *item.kind {
         clean::ModuleItem(ref m) => {
             if m.is_crate {
@@ -1788,7 +1759,36 @@ fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer) {
     }
     write!(buf, "<a class=\"{}\" href=\"\">{}</a>", item.type_(), item.name.as_ref().unwrap());
 
-    write!(buf, "</span></h1>"); // in-band
+    write!(buf, "</span>"); // in-band
+    write!(buf, "<span class=\"out-of-band\">");
+    render_stability_since_raw(
+        buf,
+        item.stable_since(cx.tcx()).as_deref(),
+        item.const_stable_since(cx.tcx()).as_deref(),
+        None,
+        None,
+    );
+    write!(
+        buf,
+        "<span id=\"render-detail\">\
+                <a id=\"toggle-all-docs\" href=\"javascript:void(0)\" \
+                    title=\"collapse all docs\">\
+                    [<span class=\"inner\">&#x2212;</span>]\
+                </a>\
+            </span>"
+    );
+
+    // Write `src` tag
+    //
+    // When this item is part of a `crate use` in a downstream crate, the
+    // [src] link in the downstream documentation will actually come back to
+    // this page, and this link will be auto-clicked. The `id` attribute is
+    // used to find the link to auto-click.
+    if cx.shared.include_sources && !item.is_primitive() {
+        write_srclink(cx, item, buf);
+    }
+
+    write!(buf, "</span></h1>"); // out-of-band
 
     match *item.kind {
         clean::ModuleItem(ref m) => item_module(buf, cx, item, &m.items),
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index bfd2141d9a1..b2e5c8834b8 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -9,9 +9,10 @@ use rustc_hir::def::CtorKind;
 use rustc_span::def_id::{DefId, CRATE_DEF_INDEX};
 use rustc_span::Pos;
 
+use rustdoc_json_types::*;
+
 use crate::clean;
 use crate::formats::item_type::ItemType;
-use crate::json::types::*;
 use crate::json::JsonRenderer;
 
 impl JsonRenderer<'_> {
@@ -22,7 +23,7 @@ impl JsonRenderer<'_> {
         match *kind {
             clean::StrippedItem(_) => None,
             kind => Some(Item {
-                id: def_id.into(),
+                id: from_def_id(def_id),
                 crate_id: def_id.krate.as_u32(),
                 name: name.map(|sym| sym.to_string()),
                 source: self.convert_span(source),
@@ -32,7 +33,7 @@ impl JsonRenderer<'_> {
                     .links
                     .into_iter()
                     .filter_map(|clean::ItemLink { link, did, .. }| {
-                        did.map(|did| (link, did.into()))
+                        did.map(|did| (link, from_def_id(did)))
                     })
                     .collect(),
                 attrs: attrs
@@ -40,7 +41,7 @@ impl JsonRenderer<'_> {
                     .iter()
                     .map(rustc_ast_pretty::pprust::attribute_to_string)
                     .collect(),
-                deprecation: deprecation.map(Into::into),
+                deprecation: deprecation.map(from_deprecation),
                 kind: item_type.into(),
                 inner: kind.into(),
             }),
@@ -74,19 +75,17 @@ impl JsonRenderer<'_> {
             Inherited => Visibility::Default,
             Restricted(did) if did.index == CRATE_DEF_INDEX => Visibility::Crate,
             Restricted(did) => Visibility::Restricted {
-                parent: did.into(),
+                parent: from_def_id(did),
                 path: self.tcx.def_path(did).to_string_no_crate_verbose(),
             },
         }
     }
 }
 
-impl From<rustc_attr::Deprecation> for Deprecation {
-    fn from(deprecation: rustc_attr::Deprecation) -> Self {
-        #[rustfmt::skip]
-        let rustc_attr::Deprecation { since, note, is_since_rustc_version: _, suggestion: _ } = deprecation;
-        Deprecation { since: since.map(|s| s.to_string()), note: note.map(|s| s.to_string()) }
-    }
+crate fn from_deprecation(deprecation: rustc_attr::Deprecation) -> Deprecation {
+    #[rustfmt::skip]
+    let rustc_attr::Deprecation { since, note, is_since_rustc_version: _, suggestion: _ } = deprecation;
+    Deprecation { since: since.map(|s| s.to_string()), note: note.map(|s| s.to_string()) }
 }
 
 impl From<clean::GenericArgs> for GenericArgs {
@@ -141,10 +140,8 @@ impl From<clean::TypeBindingKind> for TypeBindingKind {
     }
 }
 
-impl From<DefId> for Id {
-    fn from(did: DefId) -> Self {
-        Id(format!("{}:{}", did.krate.as_u32(), u32::from(did.index)))
-    }
+crate fn from_def_id(did: DefId) -> Id {
+    Id(format!("{}:{}", did.krate.as_u32(), u32::from(did.index)))
 }
 
 impl From<clean::ItemKind> for ItemEnum {
@@ -199,7 +196,7 @@ impl From<clean::Struct> for Struct {
     fn from(struct_: clean::Struct) -> Self {
         let clean::Struct { struct_type, generics, fields, fields_stripped } = struct_;
         Struct {
-            struct_type: struct_type.into(),
+            struct_type: from_ctor_kind(struct_type),
             generics: generics.into(),
             fields_stripped,
             fields: ids(fields),
@@ -221,13 +218,11 @@ impl From<clean::Union> for Struct {
     }
 }
 
-impl From<CtorKind> for StructType {
-    fn from(struct_type: CtorKind) -> Self {
-        match struct_type {
-            CtorKind::Fictive => StructType::Plain,
-            CtorKind::Fn => StructType::Tuple,
-            CtorKind::Const => StructType::Unit,
-        }
+crate fn from_ctor_kind(struct_type: CtorKind) -> StructType {
+    match struct_type {
+        CtorKind::Fictive => StructType::Plain,
+        CtorKind::Fn => StructType::Tuple,
+        CtorKind::Const => StructType::Unit,
     }
 }
 
@@ -310,7 +305,7 @@ impl From<clean::GenericBound> for GenericBound {
                 GenericBound::TraitBound {
                     trait_: trait_.into(),
                     generic_params: generic_params.into_iter().map(Into::into).collect(),
-                    modifier: modifier.into(),
+                    modifier: from_trait_bound_modifier(modifier),
                 }
             }
             Outlives(lifetime) => GenericBound::Outlives(lifetime.0.to_string()),
@@ -318,14 +313,12 @@ impl From<clean::GenericBound> for GenericBound {
     }
 }
 
-impl From<rustc_hir::TraitBoundModifier> for TraitBoundModifier {
-    fn from(modifier: rustc_hir::TraitBoundModifier) -> Self {
-        use rustc_hir::TraitBoundModifier::*;
-        match modifier {
-            None => TraitBoundModifier::None,
-            Maybe => TraitBoundModifier::Maybe,
-            MaybeConst => TraitBoundModifier::MaybeConst,
-        }
+crate fn from_trait_bound_modifier(modifier: rustc_hir::TraitBoundModifier) -> TraitBoundModifier {
+    use rustc_hir::TraitBoundModifier::*;
+    match modifier {
+        None => TraitBoundModifier::None,
+        Maybe => TraitBoundModifier::Maybe,
+        MaybeConst => TraitBoundModifier::MaybeConst,
     }
 }
 
@@ -335,7 +328,7 @@ impl From<clean::Type> for Type {
         match ty {
             ResolvedPath { path, param_names, did, is_generic: _ } => Type::ResolvedPath {
                 name: path.whole_name(),
-                id: did.into(),
+                id: from_def_id(did),
                 args: path.segments.last().map(|args| Box::new(args.clone().args.into())),
                 param_names: param_names
                     .map(|v| v.into_iter().map(Into::into).collect())
@@ -470,7 +463,7 @@ impl From<clean::VariantStruct> for Struct {
     fn from(struct_: clean::VariantStruct) -> Self {
         let clean::VariantStruct { struct_type, fields, fields_stripped } = struct_;
         Struct {
-            struct_type: struct_type.into(),
+            struct_type: from_ctor_kind(struct_type),
             generics: Default::default(),
             fields_stripped,
             fields: ids(fields),
@@ -497,13 +490,13 @@ impl From<clean::Import> for Import {
             Simple(s) => Import {
                 span: import.source.path.whole_name(),
                 name: s.to_string(),
-                id: import.source.did.map(Into::into),
+                id: import.source.did.map(from_def_id),
                 glob: false,
             },
             Glob => Import {
                 span: import.source.path.whole_name(),
                 name: import.source.path.last_name().to_string(),
-                id: import.source.did.map(Into::into),
+                id: import.source.did.map(from_def_id),
                 glob: true,
             },
         }
@@ -513,20 +506,18 @@ impl From<clean::Import> for Import {
 impl From<clean::ProcMacro> for ProcMacro {
     fn from(mac: clean::ProcMacro) -> Self {
         ProcMacro {
-            kind: mac.kind.into(),
+            kind: from_macro_kind(mac.kind),
             helpers: mac.helpers.iter().map(|x| x.to_string()).collect(),
         }
     }
 }
 
-impl From<rustc_span::hygiene::MacroKind> for MacroKind {
-    fn from(kind: rustc_span::hygiene::MacroKind) -> Self {
-        use rustc_span::hygiene::MacroKind::*;
-        match kind {
-            Bang => MacroKind::Bang,
-            Attr => MacroKind::Attr,
-            Derive => MacroKind::Derive,
-        }
+crate fn from_macro_kind(kind: rustc_span::hygiene::MacroKind) -> MacroKind {
+    use rustc_span::hygiene::MacroKind::*;
+    match kind {
+        Bang => MacroKind::Bang,
+        Attr => MacroKind::Attr,
+        Derive => MacroKind::Derive,
     }
 }
 
@@ -599,5 +590,5 @@ impl From<ItemType> for ItemKind {
 }
 
 fn ids(items: impl IntoIterator<Item = clean::Item>) -> Vec<Id> {
-    items.into_iter().filter(|x| !x.is_stripped()).map(|i| i.def_id.into()).collect()
+    items.into_iter().filter(|x| !x.is_stripped()).map(|i| from_def_id(i.def_id)).collect()
 }
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index a8a4b74b818..a7c875fb748 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -5,7 +5,6 @@
 //! docs for usage and details.
 
 mod conversions;
-pub mod types;
 
 use std::cell::RefCell;
 use std::fs::File;
@@ -17,12 +16,15 @@ use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_span::edition::Edition;
 
+use rustdoc_json_types as types;
+
 use crate::clean;
 use crate::config::{RenderInfo, RenderOptions};
 use crate::error::Error;
 use crate::formats::cache::Cache;
 use crate::formats::FormatRenderer;
 use crate::html::render::cache::ExternalLocation;
+use crate::json::conversions::from_def_id;
 
 #[derive(Clone)]
 crate struct JsonRenderer<'tcx> {
@@ -50,7 +52,7 @@ impl JsonRenderer<'_> {
                     .map(|i| {
                         let item = &i.impl_item;
                         self.item(item.clone()).unwrap();
-                        item.def_id.into()
+                        from_def_id(item.def_id)
                     })
                     .collect()
             })
@@ -68,7 +70,7 @@ impl JsonRenderer<'_> {
                         let item = &i.impl_item;
                         if item.def_id.is_local() {
                             self.item(item.clone()).unwrap();
-                            Some(item.def_id.into())
+                            Some(from_def_id(item.def_id))
                         } else {
                             None
                         }
@@ -87,9 +89,9 @@ impl JsonRenderer<'_> {
                 if !id.is_local() {
                     trait_item.items.clone().into_iter().for_each(|i| self.item(i).unwrap());
                     Some((
-                        id.into(),
+                        from_def_id(id),
                         types::Item {
-                            id: id.into(),
+                            id: from_def_id(id),
                             crate_id: id.krate.as_u32(),
                             name: self
                                 .cache
@@ -163,7 +165,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
             } else if let types::ItemEnum::EnumItem(ref mut e) = new_item.inner {
                 e.impls = self.get_impls(id)
             }
-            let removed = self.index.borrow_mut().insert(id.into(), new_item.clone());
+            let removed = self.index.borrow_mut().insert(from_def_id(id), new_item.clone());
             // FIXME(adotinthevoid): Currently, the index is duplicated. This is a sanity check
             // to make sure the items are unique.
             if let Some(old_item) = removed {
@@ -203,11 +205,14 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
         debug!("Done with crate");
         let mut index = (*self.index).clone().into_inner();
         index.extend(self.get_trait_items());
+        // This needs to be the default HashMap for compatibility with the public interface for
+        // rustdoc-json
+        #[allow(rustc::default_hash_types)]
         let output = types::Crate {
             root: types::Id(String::from("0:0")),
             crate_version: krate.version.clone(),
             includes_private: self.cache.document_private,
-            index,
+            index: index.into_iter().collect(),
             paths: self
                 .cache
                 .paths
@@ -216,7 +221,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
                 .chain(self.cache.external_paths.clone().into_iter())
                 .map(|(k, (path, kind))| {
                     (
-                        k.into(),
+                        from_def_id(k),
                         types::ItemSummary { crate_id: k.krate.as_u32(), path, kind: kind.into() },
                     )
                 })
diff --git a/src/rustdoc-json-types/Cargo.toml b/src/rustdoc-json-types/Cargo.toml
new file mode 100644
index 00000000000..7bba16a68b9
--- /dev/null
+++ b/src/rustdoc-json-types/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "rustdoc-json-types"
+version = "0.1.0"
+authors = ["The Rust Project Developers"]
+edition = "2018"
+
+[lib]
+path = "lib.rs"
+
+[dependencies]
+serde = { version = "1.0", features = ["derive"] }
diff --git a/src/rustdoc-json-types/README.md b/src/rustdoc-json-types/README.md
new file mode 100644
index 00000000000..1e67d37655c
--- /dev/null
+++ b/src/rustdoc-json-types/README.md
@@ -0,0 +1,12 @@
+# Rustdoc JSON Types
+
+This crate exposes the Rustdoc JSON API as a set of types with serde implementations.
+These types are part of the public interface of the rustdoc JSON output, and making them
+their own crate allows them to be versioned and distributed without having to depend on
+any rustc/rustdoc internals. This way, consumers can rely on this crate for both documentation
+of the output, and as a way to read the output easily, and its versioning is intended to
+follow semver guarantees about the version of the format. JSON format X will always be
+compatible with rustdoc-json-types version N.
+
+Currently, this crate is only used by rustdoc itself. Upon the stabilization of
+rustdoc-json, it may be distributed separately for consumers of the API.
diff --git a/src/librustdoc/json/types.rs b/src/rustdoc-json-types/lib.rs
index 66cf12954dd..3fb2a32d5a0 100644
--- a/src/librustdoc/json/types.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -3,9 +3,9 @@
 //! These types are the public API exposed through the `--output-format json` flag. The [`Crate`]
 //! struct is the root of the JSON blob and all other items are contained within.
 
+use std::collections::HashMap;
 use std::path::PathBuf;
 
-use rustc_data_structures::fx::FxHashMap;
 use serde::{Deserialize, Serialize};
 
 /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
@@ -21,11 +21,11 @@ pub struct Crate {
     pub includes_private: bool,
     /// A collection of all items in the local crate as well as some external traits and their
     /// items that are referenced locally.
-    pub index: FxHashMap<Id, Item>,
+    pub index: HashMap<Id, Item>,
     /// Maps IDs to fully qualified paths and other info helpful for generating links.
-    pub paths: FxHashMap<Id, ItemSummary>,
+    pub paths: HashMap<Id, ItemSummary>,
     /// Maps `crate_id` of items to a crate name and html_root_url if it exists.
-    pub external_crates: FxHashMap<u32, ExternalCrate>,
+    pub external_crates: HashMap<u32, ExternalCrate>,
     /// A single version number to be used in the future when making backwards incompatible changes
     /// to the JSON output.
     pub format_version: u32,
@@ -72,7 +72,7 @@ pub struct Item {
     /// Some("") if there is some documentation but it is empty (EG `#[doc = ""]`).
     pub docs: Option<String>,
     /// This mapping resolves [intra-doc links](https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md) from the docstring to their IDs
-    pub links: FxHashMap<String, Id>,
+    pub links: HashMap<String, Id>,
     /// Stringified versions of the attributes on this item (e.g. `"#[inline]"`)
     pub attrs: Vec<String>,
     pub deprecation: Option<Deprecation>,
diff --git a/src/test/run-make-fulldeps/split-debuginfo/Makefile b/src/test/run-make-fulldeps/split-debuginfo/Makefile
new file mode 100644
index 00000000000..e8e62efe01c
--- /dev/null
+++ b/src/test/run-make-fulldeps/split-debuginfo/Makefile
@@ -0,0 +1,59 @@
+-include ../tools.mk
+
+all: off packed unpacked
+
+ifeq ($(UNAME),Darwin)
+# If disabled, don't run dsymutil
+off:
+	rm -rf $(TMPDIR)/*.dSYM
+	$(RUSTC) foo.rs -g -C split-debuginfo=off
+	[ ! -d $(TMPDIR)/foo.dSYM ]
+
+# Packed by default, but only if debuginfo is requested
+packed:
+	rm -rf $(TMPDIR)/*.dSYM
+	$(RUSTC) foo.rs
+	[ ! -d $(TMPDIR)/foo.dSYM ]
+	rm -rf $(TMPDIR)/*.dSYM
+	$(RUSTC) foo.rs -g
+	[ -d $(TMPDIR)/foo.dSYM ]
+	rm -rf $(TMPDIR)/*.dSYM
+	$(RUSTC) foo.rs -g -C split-debuginfo=packed
+	[ -d $(TMPDIR)/foo.dSYM ]
+	rm -rf $(TMPDIR)/*.dSYM
+
+# Object files are preserved with unpacked and `dsymutil` isn't run
+unpacked:
+	$(RUSTC) foo.rs -g -C split-debuginfo=unpacked
+	ls $(TMPDIR)/*.o
+	[ ! -d $(TMPDIR)/foo.dSYM ]
+else
+ifdef IS_WINDOWS
+# Windows only supports =off
+off:
+packed:
+unpacked:
+else
+# If disabled, don't run dsymutil
+off:
+	$(RUSTC) foo.rs -g -C split-debuginfo=off -Z unstable-options
+	[ ! -f $(TMPDIR)/*.dwp ]
+	[ ! -f $(TMPDIR)/*.dwo ]
+
+	$(RUSTC) foo.rs -g
+	[ ! -f $(TMPDIR)/*.dwp ]
+	[ ! -f $(TMPDIR)/*.dwo ]
+
+packed:
+	$(RUSTC) foo.rs -g -C split-debuginfo=packed -Z unstable-options
+	ls $(TMPDIR)/*.dwp
+	ls $(TMPDIR)/*.dwo && exit 1 || exit 0
+	rm -rf $(TMPDIR)/*.dwp
+
+unpacked:
+	$(RUSTC) foo.rs -g -C split-debuginfo=unpacked -Z unstable-options
+	ls $(TMPDIR)/*.dwp && exit 1 || exit 0
+	ls $(TMPDIR)/*.dwo
+	rm -rf $(TMPDIR)/*.dwo
+endif
+endif
diff --git a/src/test/run-make-fulldeps/split-debuginfo/foo.rs b/src/test/run-make-fulldeps/split-debuginfo/foo.rs
new file mode 100644
index 00000000000..f328e4d9d04
--- /dev/null
+++ b/src/test/run-make-fulldeps/split-debuginfo/foo.rs
@@ -0,0 +1 @@
+fn main() {}
diff --git a/src/test/run-make-fulldeps/split-dwarf/Makefile b/src/test/run-make-fulldeps/split-dwarf/Makefile
index e1a78e2edfc..93dfc8e76a9 100644
--- a/src/test/run-make-fulldeps/split-dwarf/Makefile
+++ b/src/test/run-make-fulldeps/split-dwarf/Makefile
@@ -3,6 +3,6 @@
 # only-linux
 
 all:
-	$(RUSTC) -Z split-dwarf=split foo.rs
+	$(RUSTC) -Z unstable-options -C split-debuginfo=packed foo.rs -g
 	rm $(TMPDIR)/foo.dwp
 	rm $(TMPDIR)/$(call BIN,foo)
diff --git a/src/test/rustdoc/fn-type.rs b/src/test/rustdoc/fn-type.rs
new file mode 100644
index 00000000000..f5e123aed9c
--- /dev/null
+++ b/src/test/rustdoc/fn-type.rs
@@ -0,0 +1,15 @@
+// ignore-tidy-linelength
+
+#![crate_name = "foo"]
+#![crate_type = "lib"]
+
+pub struct Foo<'a, T> {
+    pub generic: fn(val: &T) -> T,
+
+    pub lifetime: fn(val: &'a i32) -> i32,
+    pub hrtb_lifetime: for<'b, 'c> fn(one: &'b i32, two: &'c &'b i32) -> (&'b i32, &'c i32),
+}
+
+// @has 'foo/struct.Foo.html' '//span[@id="structfield.generic"]' "generic: fn(val: &T) -> T"
+// @has 'foo/struct.Foo.html' '//span[@id="structfield.lifetime"]' "lifetime: fn(val: &'a i32) -> i32"
+// @has 'foo/struct.Foo.html' '//span[@id="structfield.hrtb_lifetime"]' "hrtb_lifetime: for<'b, 'c> fn(one: &'b i32, two: &'c &'b i32) -> (&'b i32, &'c i32)"
diff --git a/src/test/rustdoc/for-lifetime.rs b/src/test/rustdoc/for-lifetime.rs
new file mode 100644
index 00000000000..299794b63b2
--- /dev/null
+++ b/src/test/rustdoc/for-lifetime.rs
@@ -0,0 +1,14 @@
+// ignore-tidy-linelength
+
+#![crate_name = "foo"]
+#![crate_type = "lib"]
+
+pub struct Foo {
+    pub some_func: for<'a> fn(val: &'a i32) -> i32,
+    pub some_trait: dyn for<'a> Trait<'a>,
+}
+
+// @has foo/struct.Foo.html '//span[@id="structfield.some_func"]' "some_func: for<'a> fn(val: &'a i32) -> i32"
+// @has foo/struct.Foo.html '//span[@id="structfield.some_trait"]' "some_trait: dyn Trait<'a>"
+
+pub trait Trait<'a> {}
diff --git a/src/test/ui/associated-consts/defaults-not-assumed-fail.rs b/src/test/ui/associated-consts/defaults-not-assumed-fail.rs
index d7a48cbd63e..b0a4c7722e3 100644
--- a/src/test/ui/associated-consts/defaults-not-assumed-fail.rs
+++ b/src/test/ui/associated-consts/defaults-not-assumed-fail.rs
@@ -31,7 +31,7 @@ impl Tr for u32 {
 fn main() {
     assert_eq!(<() as Tr>::A, 255);
     assert_eq!(<() as Tr>::B, 0);    // causes the error above
-    //~^ ERROR evaluation of constant expression failed
+    //~^ ERROR evaluation of constant value failed
     //~| ERROR erroneous constant used
 
     assert_eq!(<u8 as Tr>::A, 254);
diff --git a/src/test/ui/associated-consts/defaults-not-assumed-fail.stderr b/src/test/ui/associated-consts/defaults-not-assumed-fail.stderr
index 1497633c26a..cbaaed0508b 100644
--- a/src/test/ui/associated-consts/defaults-not-assumed-fail.stderr
+++ b/src/test/ui/associated-consts/defaults-not-assumed-fail.stderr
@@ -8,15 +8,11 @@ LL |     const B: u8 = Self::A + 1;
    |
    = note: `#[deny(const_err)]` on by default
 
-error[E0080]: evaluation of constant expression failed
-  --> $DIR/defaults-not-assumed-fail.rs:33:5
+error[E0080]: evaluation of constant value failed
+  --> $DIR/defaults-not-assumed-fail.rs:33:16
    |
 LL |     assert_eq!(<() as Tr>::B, 0);    // causes the error above
-   |     ^^^^^^^^^^^-------------^^^^^
-   |                |
-   |                referenced constant has errors
-   |
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+   |                ^^^^^^^^^^^^^ referenced constant has errors
 
 error: erroneous constant used
   --> $DIR/defaults-not-assumed-fail.rs:33:5
diff --git a/src/test/ui/backtrace-apple-no-dsymutil.rs b/src/test/ui/backtrace-apple-no-dsymutil.rs
new file mode 100644
index 00000000000..492ff6356bc
--- /dev/null
+++ b/src/test/ui/backtrace-apple-no-dsymutil.rs
@@ -0,0 +1,30 @@
+// run-pass
+
+// compile-flags:-g -Csplit-debuginfo=unpacked
+// only-macos
+
+#![feature(backtrace)]
+
+use std::process::Command;
+use std::str;
+
+#[inline(never)]
+fn main() {
+    let args: Vec<String> = std::env::args().collect();
+    if args.len() >= 2 {
+        println!("{}", std::backtrace::Backtrace::force_capture());
+        return;
+    }
+    let out = Command::new(&args[0]).env("RUST_BACKTRACE", "1").arg("foo").output().unwrap();
+    let output = format!(
+        "{}\n{}",
+        str::from_utf8(&out.stdout).unwrap(),
+        str::from_utf8(&out.stderr).unwrap(),
+    );
+    if out.status.success() && output.contains(file!()) {
+        return;
+    }
+    println!("status: {}", out.status);
+    println!("child output:\n\t{}", output.replace("\n", "\n\t"));
+    panic!("failed to find {:?} in output", file!());
+}
diff --git a/src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr b/src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr
index 44dde0fd80b..ea74fb96684 100644
--- a/src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr
+++ b/src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr
@@ -20,7 +20,9 @@ error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
    |
 LL |     let f = || {
    |         - help: consider changing this to be mutable: `mut f`
-...
+LL |         let y = &raw mut x;
+   |                          - calling `f` requires mutable binding due to mutable borrow of `x`
+LL |     };
 LL |     f();
    |     ^ cannot borrow as mutable
 
diff --git a/src/test/ui/closures/issue-80313-mutable-borrow-in-closure.rs b/src/test/ui/closures/issue-80313-mutable-borrow-in-closure.rs
new file mode 100644
index 00000000000..ff210ae06a3
--- /dev/null
+++ b/src/test/ui/closures/issue-80313-mutable-borrow-in-closure.rs
@@ -0,0 +1,7 @@
+fn main() {
+    let mut my_var = false;
+    let callback = || {
+        &mut my_var;
+    };
+    callback(); //~ ERROR E0596
+}
diff --git a/src/test/ui/closures/issue-80313-mutable-borrow-in-closure.stderr b/src/test/ui/closures/issue-80313-mutable-borrow-in-closure.stderr
new file mode 100644
index 00000000000..bf9e1febdbb
--- /dev/null
+++ b/src/test/ui/closures/issue-80313-mutable-borrow-in-closure.stderr
@@ -0,0 +1,14 @@
+error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable
+  --> $DIR/issue-80313-mutable-borrow-in-closure.rs:6:5
+   |
+LL |     let callback = || {
+   |         -------- help: consider changing this to be mutable: `mut callback`
+LL |         &mut my_var;
+   |              ------ calling `callback` requires mutable binding due to mutable borrow of `my_var`
+LL |     };
+LL |     callback();
+   |     ^^^^^^^^ cannot borrow as mutable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/src/test/ui/closures/issue-80313-mutable-borrow-in-move-closure.rs b/src/test/ui/closures/issue-80313-mutable-borrow-in-move-closure.rs
new file mode 100644
index 00000000000..8f2d8a67630
--- /dev/null
+++ b/src/test/ui/closures/issue-80313-mutable-borrow-in-move-closure.rs
@@ -0,0 +1,7 @@
+fn main() {
+    let mut my_var = false;
+    let callback = move || {
+        &mut my_var;
+    };
+    callback(); //~ ERROR E0596
+}
diff --git a/src/test/ui/closures/issue-80313-mutable-borrow-in-move-closure.stderr b/src/test/ui/closures/issue-80313-mutable-borrow-in-move-closure.stderr
new file mode 100644
index 00000000000..b67cec6a609
--- /dev/null
+++ b/src/test/ui/closures/issue-80313-mutable-borrow-in-move-closure.stderr
@@ -0,0 +1,14 @@
+error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable
+  --> $DIR/issue-80313-mutable-borrow-in-move-closure.rs:6:5
+   |
+LL |     let callback = move || {
+   |         -------- help: consider changing this to be mutable: `mut callback`
+LL |         &mut my_var;
+   |              ------ calling `callback` requires mutable binding due to possible mutation of `my_var`
+LL |     };
+LL |     callback();
+   |     ^^^^^^^^ cannot borrow as mutable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/src/test/ui/closures/issue-80313-mutation-in-closure.rs b/src/test/ui/closures/issue-80313-mutation-in-closure.rs
new file mode 100644
index 00000000000..e082ea562ef
--- /dev/null
+++ b/src/test/ui/closures/issue-80313-mutation-in-closure.rs
@@ -0,0 +1,7 @@
+fn main() {
+    let mut my_var = false;
+    let callback = || {
+        my_var = true;
+    };
+    callback(); //~ ERROR E0596
+}
diff --git a/src/test/ui/closures/issue-80313-mutation-in-closure.stderr b/src/test/ui/closures/issue-80313-mutation-in-closure.stderr
new file mode 100644
index 00000000000..6e98549f6b8
--- /dev/null
+++ b/src/test/ui/closures/issue-80313-mutation-in-closure.stderr
@@ -0,0 +1,14 @@
+error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable
+  --> $DIR/issue-80313-mutation-in-closure.rs:6:5
+   |
+LL |     let callback = || {
+   |         -------- help: consider changing this to be mutable: `mut callback`
+LL |         my_var = true;
+   |         ------ calling `callback` requires mutable binding due to mutable borrow of `my_var`
+LL |     };
+LL |     callback();
+   |     ^^^^^^^^ cannot borrow as mutable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/src/test/ui/closures/issue-80313-mutation-in-move-closure.rs b/src/test/ui/closures/issue-80313-mutation-in-move-closure.rs
new file mode 100644
index 00000000000..f66bf4e0628
--- /dev/null
+++ b/src/test/ui/closures/issue-80313-mutation-in-move-closure.rs
@@ -0,0 +1,7 @@
+fn main() {
+    let mut my_var = false;
+    let callback = move || {
+        my_var = true;
+    };
+    callback(); //~ ERROR E0596
+}
diff --git a/src/test/ui/closures/issue-80313-mutation-in-move-closure.stderr b/src/test/ui/closures/issue-80313-mutation-in-move-closure.stderr
new file mode 100644
index 00000000000..edd55422a0b
--- /dev/null
+++ b/src/test/ui/closures/issue-80313-mutation-in-move-closure.stderr
@@ -0,0 +1,14 @@
+error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable
+  --> $DIR/issue-80313-mutation-in-move-closure.rs:6:5
+   |
+LL |     let callback = move || {
+   |         -------- help: consider changing this to be mutable: `mut callback`
+LL |         my_var = true;
+   |         ------ calling `callback` requires mutable binding due to possible mutation of `my_var`
+LL |     };
+LL |     callback();
+   |     ^^^^^^^^ cannot borrow as mutable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/src/test/ui/consts/const-eval/conditional_array_execution.stderr b/src/test/ui/consts/const-eval/conditional_array_execution.stderr
index 65dfbd8097e..c2adff116ef 100644
--- a/src/test/ui/consts/const-eval/conditional_array_execution.stderr
+++ b/src/test/ui/consts/const-eval/conditional_array_execution.stderr
@@ -12,7 +12,7 @@ note: the lint level is defined here
 LL | #![warn(const_err)]
    |         ^^^^^^^^^
 
-error[E0080]: evaluation of constant expression failed
+error[E0080]: evaluation of constant value failed
   --> $DIR/conditional_array_execution.rs:11:20
    |
 LL |     println!("{}", FOO);
diff --git a/src/test/ui/consts/const-eval/const-eval-query-stack.rs b/src/test/ui/consts/const-eval/const-eval-query-stack.rs
index 39803c8f257..cbfeca24026 100644
--- a/src/test/ui/consts/const-eval/const-eval-query-stack.rs
+++ b/src/test/ui/consts/const-eval/const-eval-query-stack.rs
@@ -21,6 +21,6 @@ const X: i32 = 1 / 0; //~WARN any use of this value will cause an error
 
 fn main() {
     let x: &'static i32 = &X;
-    //~^ ERROR evaluation of constant expression failed
+    //~^ ERROR evaluation of constant value failed
     println!("x={}", x);
 }
diff --git a/src/test/ui/consts/const-eval/const-eval-query-stack.stderr b/src/test/ui/consts/const-eval/const-eval-query-stack.stderr
index 0016d301e59..3e727b84aed 100644
--- a/src/test/ui/consts/const-eval/const-eval-query-stack.stderr
+++ b/src/test/ui/consts/const-eval/const-eval-query-stack.stderr
@@ -12,13 +12,11 @@ note: the lint level is defined here
 LL | #[warn(const_err)]
    |        ^^^^^^^^^
 
-error[E0080]: evaluation of constant expression failed
-  --> $DIR/const-eval-query-stack.rs:23:27
+error[E0080]: evaluation of constant value failed
+  --> $DIR/const-eval-query-stack.rs:23:28
    |
 LL |     let x: &'static i32 = &X;
-   |                           ^-
-   |                            |
-   |                            referenced constant has errors
+   |                            ^ referenced constant has errors
 query stack during panic:
 #0 [normalize_generic_arg_after_erasing_regions] normalizing `main::promoted[1]`
 #1 [optimized_mir] optimizing MIR for `main`
diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs
index f67871e6142..0a2532973f4 100644
--- a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs
+++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs
@@ -18,7 +18,7 @@ const Z: usize = bar(double, 2); // FIXME: should fail to typeck someday
 
 fn main() {
     assert_eq!(Y, 4);
-    //~^ ERROR evaluation of constant expression failed
+    //~^ ERROR evaluation of constant value failed
     assert_eq!(Z, 4);
-    //~^ ERROR evaluation of constant expression failed
+    //~^ ERROR evaluation of constant value failed
 }
diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr
index 822d4af8306..2afedf30563 100644
--- a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr
+++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr
@@ -1,22 +1,14 @@
-error[E0080]: evaluation of constant expression failed
-  --> $DIR/const_fn_ptr_fail2.rs:20:5
+error[E0080]: evaluation of constant value failed
+  --> $DIR/const_fn_ptr_fail2.rs:20:16
    |
 LL |     assert_eq!(Y, 4);
-   |     ^^^^^^^^^^^-^^^^^
-   |                |
-   |                referenced constant has errors
-   |
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+   |                ^ referenced constant has errors
 
-error[E0080]: evaluation of constant expression failed
-  --> $DIR/const_fn_ptr_fail2.rs:22:5
+error[E0080]: evaluation of constant value failed
+  --> $DIR/const_fn_ptr_fail2.rs:22:16
    |
 LL |     assert_eq!(Z, 4);
-   |     ^^^^^^^^^^^-^^^^^
-   |                |
-   |                referenced constant has errors
-   |
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+   |                ^ referenced constant has errors
 
 warning: skipping const checks
    |
diff --git a/src/test/ui/consts/const-eval/issue-43197.rs b/src/test/ui/consts/const-eval/issue-43197.rs
index 9109307632b..7d1d33288a9 100644
--- a/src/test/ui/consts/const-eval/issue-43197.rs
+++ b/src/test/ui/consts/const-eval/issue-43197.rs
@@ -12,8 +12,8 @@ fn main() {
     const Y: u32 = foo(0 - 1);
     //~^ WARN any use of this value will cause
     println!("{} {}", X, Y);
-    //~^ ERROR evaluation of constant expression failed
-    //~| ERROR evaluation of constant expression failed
+    //~^ ERROR evaluation of constant value failed
+    //~| ERROR evaluation of constant value failed
     //~| WARN erroneous constant used [const_err]
     //~| WARN erroneous constant used [const_err]
 }
diff --git a/src/test/ui/consts/const-eval/issue-43197.stderr b/src/test/ui/consts/const-eval/issue-43197.stderr
index 27e067cedbb..8c72b591416 100644
--- a/src/test/ui/consts/const-eval/issue-43197.stderr
+++ b/src/test/ui/consts/const-eval/issue-43197.stderr
@@ -20,7 +20,7 @@ LL |     const Y: u32 = foo(0 - 1);
    |                        |
    |                        attempt to compute `0_u32 - 1_u32`, which would overflow
 
-error[E0080]: evaluation of constant expression failed
+error[E0080]: evaluation of constant value failed
   --> $DIR/issue-43197.rs:14:23
    |
 LL |     println!("{} {}", X, Y);
@@ -32,7 +32,7 @@ warning: erroneous constant used
 LL |     println!("{} {}", X, Y);
    |                       ^ referenced constant has errors
 
-error[E0080]: evaluation of constant expression failed
+error[E0080]: evaluation of constant value failed
   --> $DIR/issue-43197.rs:14:26
    |
 LL |     println!("{} {}", X, Y);
diff --git a/src/test/ui/consts/const-eval/issue-44578.rs b/src/test/ui/consts/const-eval/issue-44578.rs
index f9194709dc0..79f1301a2f9 100644
--- a/src/test/ui/consts/const-eval/issue-44578.rs
+++ b/src/test/ui/consts/const-eval/issue-44578.rs
@@ -25,5 +25,5 @@ impl Foo for u16 {
 
 fn main() {
     println!("{}", <Bar<u16, u8> as Foo>::AMT);
-    //~^ ERROR evaluation of constant expression failed [E0080]
+    //~^ ERROR evaluation of constant value failed [E0080]
 }
diff --git a/src/test/ui/consts/const-eval/issue-44578.stderr b/src/test/ui/consts/const-eval/issue-44578.stderr
index f4323713e68..bff9f40f82b 100644
--- a/src/test/ui/consts/const-eval/issue-44578.stderr
+++ b/src/test/ui/consts/const-eval/issue-44578.stderr
@@ -1,4 +1,4 @@
-error[E0080]: evaluation of constant expression failed
+error[E0080]: evaluation of constant value failed
   --> $DIR/issue-44578.rs:27:20
    |
 LL |     println!("{}", <Bar<u16, u8> as Foo>::AMT);
diff --git a/src/test/ui/consts/const-eval/issue-50814-2.stderr b/src/test/ui/consts/const-eval/issue-50814-2.stderr
index ca8885e9350..f929f500cf9 100644
--- a/src/test/ui/consts/const-eval/issue-50814-2.stderr
+++ b/src/test/ui/consts/const-eval/issue-50814-2.stderr
@@ -8,13 +8,11 @@ LL |     const BAR: usize = [5, 6, 7][T::BOO];
    |
    = note: `#[deny(const_err)]` on by default
 
-error[E0080]: evaluation of constant expression failed
-  --> $DIR/issue-50814-2.rs:18:5
+error[E0080]: evaluation of constant value failed
+  --> $DIR/issue-50814-2.rs:18:6
    |
 LL |     &<A<T> as Foo<T>>::BAR
-   |     ^---------------------
-   |      |
-   |      referenced constant has errors
+   |      ^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/consts/const-eval/issue-50814.stderr b/src/test/ui/consts/const-eval/issue-50814.stderr
index 73271386276..307fb3c8c9d 100644
--- a/src/test/ui/consts/const-eval/issue-50814.stderr
+++ b/src/test/ui/consts/const-eval/issue-50814.stderr
@@ -8,13 +8,11 @@ LL |     const MAX: u8 = A::MAX + B::MAX;
    |
    = note: `#[deny(const_err)]` on by default
 
-error[E0080]: evaluation of constant expression failed
-  --> $DIR/issue-50814.rs:20:5
+error[E0080]: evaluation of constant value failed
+  --> $DIR/issue-50814.rs:20:6
    |
 LL |     &Sum::<U8,U8>::MAX
-   |     ^-----------------
-   |      |
-   |      referenced constant has errors
+   |      ^^^^^^^^^^^^^^^^^ referenced constant has errors
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/consts/const_unsafe_unreachable_ub.stderr b/src/test/ui/consts/const_unsafe_unreachable_ub.stderr
index 31090be0908..6dddc7ff6e9 100644
--- a/src/test/ui/consts/const_unsafe_unreachable_ub.stderr
+++ b/src/test/ui/consts/const_unsafe_unreachable_ub.stderr
@@ -20,15 +20,11 @@ note: the lint level is defined here
 LL | #[warn(const_err)]
    |        ^^^^^^^^^
 
-error[E0080]: evaluation of constant expression failed
-  --> $DIR/const_unsafe_unreachable_ub.rs:17:3
+error[E0080]: evaluation of constant value failed
+  --> $DIR/const_unsafe_unreachable_ub.rs:17:14
    |
 LL |   assert_eq!(BAR, true);
-   |   ^^^^^^^^^^^---^^^^^^^^
-   |              |
-   |              referenced constant has errors
-   |
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+   |              ^^^ referenced constant has errors
 
 error: erroneous constant used
   --> $DIR/const_unsafe_unreachable_ub.rs:17:3
diff --git a/src/test/ui/consts/issue-55878.stderr b/src/test/ui/consts/issue-55878.stderr
index 924910e9cb6..ede5487b65d 100644
--- a/src/test/ui/consts/issue-55878.stderr
+++ b/src/test/ui/consts/issue-55878.stderr
@@ -2,15 +2,12 @@ error[E0080]: values of the type `[u8; SIZE]` are too big for the current archit
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
 LL |     intrinsics::size_of::<T>()
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |     |
-   |     inside `std::mem::size_of::<[u8; SIZE]>` at $SRC_DIR/core/src/mem/mod.rs:LL:COL
-   |     inside `main` at $DIR/issue-55878.rs:7:26
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ inside `std::mem::size_of::<[u8; SIZE]>` at $SRC_DIR/core/src/mem/mod.rs:LL:COL
    | 
   ::: $DIR/issue-55878.rs:7:26
    |
 LL |     println!("Size: {}", std::mem::size_of::<[u8; u64::MAX as usize]>());
-   |                          ----------------------------------------------
+   |                          ---------------------------------------------- inside `main` at $DIR/issue-55878.rs:7:26
 
 error: erroneous constant used
   --> $DIR/issue-55878.rs:7:26
diff --git a/src/test/ui/lint/semicolon-in-expressions-from-macros/allow-semicolon-in-expressions-from-macros.rs b/src/test/ui/lint/semicolon-in-expressions-from-macros/allow-semicolon-in-expressions-from-macros.rs
new file mode 100644
index 00000000000..6f9e6ec0a57
--- /dev/null
+++ b/src/test/ui/lint/semicolon-in-expressions-from-macros/allow-semicolon-in-expressions-from-macros.rs
@@ -0,0 +1,15 @@
+// check-pass
+// Ensure that trailing semicolons are allowed by default
+
+macro_rules! foo {
+    () => {
+        true;
+    }
+}
+
+fn main() {
+    let val = match true {
+        true => false,
+        _ => foo!()
+    };
+}
diff --git a/src/test/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.rs b/src/test/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.rs
new file mode 100644
index 00000000000..605d5a0309c
--- /dev/null
+++ b/src/test/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.rs
@@ -0,0 +1,30 @@
+// check-pass
+#![warn(semicolon_in_expressions_from_macros)]
+
+#[allow(dead_code)]
+macro_rules! foo {
+    ($val:ident) => {
+        true; //~ WARN trailing
+              //~| WARN this was previously
+              //~| WARN trailing
+              //~| WARN this was previously
+    }
+}
+
+fn main() {
+    // This `allow` doesn't work
+    #[allow(semicolon_in_expressions_from_macros)]
+    let _ = {
+        foo!(first)
+    };
+
+    // This 'allow' doesn't work either
+    #[allow(semicolon_in_expressions_from_macros)]
+    let _ = foo!(second);
+
+    // But this 'allow' does
+    #[allow(semicolon_in_expressions_from_macros)]
+    fn inner() {
+        let _ = foo!(third);
+    }
+}
diff --git a/src/test/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr b/src/test/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr
new file mode 100644
index 00000000000..6f9f879661a
--- /dev/null
+++ b/src/test/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr
@@ -0,0 +1,33 @@
+warning: trailing semicolon in macro used in expression position
+  --> $DIR/semicolon-in-expressions-from-macros.rs:7:13
+   |
+LL |         true;
+   |             ^
+...
+LL |         foo!(first)
+   |         ----------- in this macro invocation
+   |
+note: the lint level is defined here
+  --> $DIR/semicolon-in-expressions-from-macros.rs:2:9
+   |
+LL | #![warn(semicolon_in_expressions_from_macros)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
+   = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: trailing semicolon in macro used in expression position
+  --> $DIR/semicolon-in-expressions-from-macros.rs:7:13
+   |
+LL |         true;
+   |             ^
+...
+LL |     let _ = foo!(second);
+   |             ------------ in this macro invocation
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
+   = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: 2 warnings emitted
+
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.stderr
index 5dea424596e..a0ed56d4bcf 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.stderr
@@ -3,6 +3,8 @@ error[E0596]: cannot borrow `tick1` as mutable, as it is not declared as mutable
    |
 LL |     let tick1 = || {
    |         ----- help: consider changing this to be mutable: `mut tick1`
+LL |         counter += 1;
+   |         ------- calling `tick1` requires mutable binding due to mutable borrow of `counter`
 ...
 LL |         tick1();
    |         ^^^^^ cannot borrow as mutable
@@ -12,6 +14,8 @@ error[E0596]: cannot borrow `tick2` as mutable, as it is not declared as mutable
    |
 LL |     let tick2 = || {
    |         ----- help: consider changing this to be mutable: `mut tick2`
+LL |         tick1();
+   |         ----- calling `tick2` requires mutable binding due to mutable borrow of `tick1`
 ...
 LL |     tick2();
    |     ^^^^^ cannot borrow as mutable
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.stderr
index eb398628846..27d23e3fa04 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.stderr
@@ -2,7 +2,9 @@ error[E0596]: cannot borrow `tick` as mutable, as it is not declared as mutable
   --> $DIR/unboxed-closures-infer-fnmut-missing-mut.rs:7:5
    |
 LL |     let tick = || counter += 1;
-   |         ---- help: consider changing this to be mutable: `mut tick`
+   |         ----      ------- calling `tick` requires mutable binding due to mutable borrow of `counter`
+   |         |
+   |         help: consider changing this to be mutable: `mut tick`
 LL |     tick();
    |     ^^^^ cannot borrow as mutable
 
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.stderr
index b9d76d9a752..c00f986c397 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.stderr
@@ -2,7 +2,9 @@ error[E0596]: cannot borrow `tick` as mutable, as it is not declared as mutable
   --> $DIR/unboxed-closures-infer-fnmut-move-missing-mut.rs:7:5
    |
 LL |     let tick = move || counter += 1;
-   |         ---- help: consider changing this to be mutable: `mut tick`
+   |         ----           ------- calling `tick` requires mutable binding due to possible mutation of `counter`
+   |         |
+   |         help: consider changing this to be mutable: `mut tick`
 LL |     tick();
    |     ^^^^ cannot borrow as mutable
 
diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs
index f7224811e6e..6fa1378b8c7 100644
--- a/src/tools/clippy/clippy_lints/src/default.rs
+++ b/src/tools/clippy/clippy_lints/src/default.rs
@@ -1,5 +1,5 @@
 use crate::utils::{
-    any_parent_is_automatically_derived, contains_name, match_def_path, paths, qpath_res, snippet_with_macro_callsite,
+    any_parent_is_automatically_derived, contains_name, match_def_path, paths, snippet_with_macro_callsite,
 };
 use crate::utils::{span_lint_and_note, span_lint_and_sugg};
 use if_chain::if_chain;
@@ -231,7 +231,7 @@ fn is_expr_default<'tcx>(expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> bool
     if_chain! {
         if let ExprKind::Call(ref fn_expr, _) = &expr.kind;
         if let ExprKind::Path(qpath) = &fn_expr.kind;
-        if let Res::Def(_, def_id) = qpath_res(cx, qpath, fn_expr.hir_id);
+        if let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id);
         then {
             // right hand side of assignment is `Default::default`
             match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD)
diff --git a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
index cf528d189b4..a84f9c46287 100644
--- a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
@@ -1,4 +1,4 @@
-use crate::utils::{is_copy, match_def_path, paths, qpath_res, span_lint_and_note};
+use crate::utils::{is_copy, match_def_path, paths, span_lint_and_note};
 use if_chain::if_chain;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -114,7 +114,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
             if let ExprKind::Call(ref path, ref args) = expr.kind;
             if let ExprKind::Path(ref qpath) = path.kind;
             if args.len() == 1;
-            if let Some(def_id) = qpath_res(cx, qpath, path.hir_id).opt_def_id();
+            if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id();
             then {
                 let lint;
                 let msg;
diff --git a/src/tools/clippy/clippy_lints/src/exit.rs b/src/tools/clippy/clippy_lints/src/exit.rs
index 7337d98c8be..91585927000 100644
--- a/src/tools/clippy/clippy_lints/src/exit.rs
+++ b/src/tools/clippy/clippy_lints/src/exit.rs
@@ -1,4 +1,4 @@
-use crate::utils::{is_entrypoint_fn, match_def_path, paths, qpath_res, span_lint};
+use crate::utils::{is_entrypoint_fn, match_def_path, paths, span_lint};
 use if_chain::if_chain;
 use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node};
 use rustc_lint::{LateContext, LateLintPass};
@@ -29,7 +29,7 @@ impl<'tcx> LateLintPass<'tcx> for Exit {
         if_chain! {
             if let ExprKind::Call(ref path_expr, ref _args) = e.kind;
             if let ExprKind::Path(ref path) = path_expr.kind;
-            if let Some(def_id) = qpath_res(cx, path, path_expr.hir_id).opt_def_id();
+            if let Some(def_id) = cx.qpath_res(path, path_expr.hir_id).opt_def_id();
             if match_def_path(cx, def_id, &paths::EXIT);
             then {
                 let parent = cx.tcx.hir().get_parent_item(e.hir_id);
diff --git a/src/tools/clippy/clippy_lints/src/functions.rs b/src/tools/clippy/clippy_lints/src/functions.rs
index fd93548b55c..87954254610 100644
--- a/src/tools/clippy/clippy_lints/src/functions.rs
+++ b/src/tools/clippy/clippy_lints/src/functions.rs
@@ -1,7 +1,7 @@
 use crate::utils::{
     attr_by_name, attrs::is_proc_macro, is_must_use_ty, is_trait_impl_item, is_type_diagnostic_item, iter_input_pats,
-    last_path_segment, match_def_path, must_use_attr, qpath_res, return_ty, snippet, snippet_opt, span_lint,
-    span_lint_and_help, span_lint_and_then, trait_ref_of_method, type_is_unsafe_function,
+    last_path_segment, match_def_path, must_use_attr, return_ty, snippet, snippet_opt, span_lint, span_lint_and_help,
+    span_lint_and_then, trait_ref_of_method, type_is_unsafe_function,
 };
 use if_chain::if_chain;
 use rustc_ast::ast::Attribute;
@@ -659,7 +659,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> {
 impl<'a, 'tcx> DerefVisitor<'a, 'tcx> {
     fn check_arg(&self, ptr: &hir::Expr<'_>) {
         if let hir::ExprKind::Path(ref qpath) = ptr.kind {
-            if let Res::Local(id) = qpath_res(self.cx, qpath, ptr.hir_id) {
+            if let Res::Local(id) = self.cx.qpath_res(qpath, ptr.hir_id) {
                 if self.ptrs.contains(&id) {
                     span_lint(
                         self.cx,
@@ -722,7 +722,7 @@ fn is_mutated_static(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool {
     use hir::ExprKind::{Field, Index, Path};
 
     match e.kind {
-        Path(ref qpath) => !matches!(qpath_res(cx, qpath, e.hir_id), Res::Local(_)),
+        Path(ref qpath) => !matches!(cx.qpath_res(qpath, e.hir_id), Res::Local(_)),
         Field(ref inner, _) | Index(ref inner, _) => is_mutated_static(cx, inner),
         _ => false,
     }
diff --git a/src/tools/clippy/clippy_lints/src/let_if_seq.rs b/src/tools/clippy/clippy_lints/src/let_if_seq.rs
index db717cd1240..5886c2360e3 100644
--- a/src/tools/clippy/clippy_lints/src/let_if_seq.rs
+++ b/src/tools/clippy/clippy_lints/src/let_if_seq.rs
@@ -1,4 +1,4 @@
-use crate::utils::{qpath_res, snippet, span_lint_and_then, visitors::LocalUsedVisitor};
+use crate::utils::{snippet, span_lint_and_then, visitors::LocalUsedVisitor};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
@@ -145,7 +145,7 @@ fn check_assign<'tcx>(
         if let hir::StmtKind::Semi(ref expr) = expr.kind;
         if let hir::ExprKind::Assign(ref var, ref value, _) = expr.kind;
         if let hir::ExprKind::Path(ref qpath) = var.kind;
-        if let Res::Local(local_id) = qpath_res(cx, qpath, var.hir_id);
+        if let Res::Local(local_id) = cx.qpath_res(qpath, var.hir_id);
         if decl == local_id;
         then {
             let mut v = LocalUsedVisitor::new(decl);
diff --git a/src/tools/clippy/clippy_lints/src/loops.rs b/src/tools/clippy/clippy_lints/src/loops.rs
index bbcea387de2..f89075005bc 100644
--- a/src/tools/clippy/clippy_lints/src/loops.rs
+++ b/src/tools/clippy/clippy_lints/src/loops.rs
@@ -6,9 +6,9 @@ use crate::utils::visitors::LocalUsedVisitor;
 use crate::utils::{
     contains_name, get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait,
     indent_of, is_in_panic_handler, is_integer_const, is_no_std_crate, is_refutable, is_type_diagnostic_item,
-    last_path_segment, match_trait_method, match_type, match_var, multispan_sugg, qpath_res, single_segment_path,
-    snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help,
-    span_lint_and_sugg, span_lint_and_then, sugg, SpanlessEq,
+    last_path_segment, match_trait_method, match_type, match_var, multispan_sugg, single_segment_path, snippet,
+    snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg,
+    span_lint_and_then, sugg, SpanlessEq,
 };
 use if_chain::if_chain;
 use rustc_ast::ast;
@@ -848,7 +848,7 @@ fn same_var<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, var: HirId) -> bool {
         if let ExprKind::Path(qpath) = &expr.kind;
         if let QPath::Resolved(None, path) = qpath;
         if path.segments.len() == 1;
-        if let Res::Local(local_id) = qpath_res(cx, qpath, expr.hir_id);
+        if let Res::Local(local_id) = cx.qpath_res(qpath, expr.hir_id);
         then {
             // our variable!
             local_id == var
@@ -1420,7 +1420,7 @@ fn detect_same_item_push<'tcx>(
                 // Make sure that the push does not involve possibly mutating values
                 match pushed_item.kind {
                     ExprKind::Path(ref qpath) => {
-                        match qpath_res(cx, qpath, pushed_item.hir_id) {
+                        match cx.qpath_res(qpath, pushed_item.hir_id) {
                             // immutable bindings that are initialized with literal or constant
                             Res::Local(hir_id) => {
                                 if_chain! {
@@ -1437,7 +1437,7 @@ fn detect_same_item_push<'tcx>(
                                             ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item),
                                             // immutable bindings that are initialized with constant
                                             ExprKind::Path(ref path) => {
-                                                if let Res::Def(DefKind::Const, ..) = qpath_res(cx, path, init.hir_id) {
+                                                if let Res::Def(DefKind::Const, ..) = cx.qpath_res(path, init.hir_id) {
                                                     emit_lint(cx, vec, pushed_item);
                                                 }
                                             }
@@ -2028,7 +2028,7 @@ fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option<HirId>
         if let ExprKind::Path(ref qpath) = bound.kind;
         if let QPath::Resolved(None, _) = *qpath;
         then {
-            let res = qpath_res(cx, qpath, bound.hir_id);
+            let res = cx.qpath_res(qpath, bound.hir_id);
             if let Res::Local(hir_id) = res {
                 let node_str = cx.tcx.hir().get(hir_id);
                 if_chain! {
@@ -2120,7 +2120,7 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> {
                     if self.prefer_mutable {
                         self.indexed_mut.insert(seqvar.segments[0].ident.name);
                     }
-                    let res = qpath_res(self.cx, seqpath, seqexpr.hir_id);
+                    let res = self.cx.qpath_res(seqpath, seqexpr.hir_id);
                     match res {
                         Res::Local(hir_id) => {
                             let parent_id = self.cx.tcx.hir().get_parent_item(expr.hir_id);
@@ -2184,7 +2184,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
             if let QPath::Resolved(None, ref path) = *qpath;
             if path.segments.len() == 1;
             then {
-                if let Res::Local(local_id) = qpath_res(self.cx, qpath, expr.hir_id) {
+                if let Res::Local(local_id) = self.cx.qpath_res(qpath, expr.hir_id) {
                     if local_id == self.var {
                         self.nonindex = true;
                     } else {
@@ -2589,7 +2589,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
 
 fn var_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<HirId> {
     if let ExprKind::Path(ref qpath) = expr.kind {
-        let path_res = qpath_res(cx, qpath, expr.hir_id);
+        let path_res = cx.qpath_res(qpath, expr.hir_id);
         if let Res::Local(hir_id) = path_res {
             return Some(hir_id);
         }
@@ -2819,7 +2819,7 @@ impl<'a, 'tcx> VarCollectorVisitor<'a, 'tcx> {
         if_chain! {
             if let ExprKind::Path(ref qpath) = ex.kind;
             if let QPath::Resolved(None, _) = *qpath;
-            let res = qpath_res(self.cx, qpath, ex.hir_id);
+            let res = self.cx.qpath_res(qpath, ex.hir_id);
             then {
                 match res {
                     Res::Local(hir_id) => {
diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs
index a0cfe145a30..42a92104a49 100644
--- a/src/tools/clippy/clippy_lints/src/manual_strip.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs
@@ -1,7 +1,7 @@
 use crate::consts::{constant, Constant};
 use crate::utils::usage::mutated_variables;
 use crate::utils::{
-    eq_expr_value, higher, match_def_path, meets_msrv, multispan_sugg, paths, qpath_res, snippet, span_lint_and_then,
+    eq_expr_value, higher, match_def_path, meets_msrv, multispan_sugg, paths, snippet, span_lint_and_then,
 };
 
 use if_chain::if_chain;
@@ -92,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
                 } else {
                     return;
                 };
-                let target_res = qpath_res(cx, &target_path, target_arg.hir_id);
+                let target_res = cx.qpath_res(&target_path, target_arg.hir_id);
                 if target_res == Res::Err {
                     return;
                 };
@@ -221,7 +221,7 @@ fn find_stripping<'tcx>(
                 if let ExprKind::Index(indexed, index) = &unref.kind;
                 if let Some(higher::Range { start, end, .. }) = higher::range(index);
                 if let ExprKind::Path(path) = &indexed.kind;
-                if qpath_res(self.cx, path, ex.hir_id) == self.target;
+                if self.cx.qpath_res(path, ex.hir_id) == self.target;
                 then {
                     match (self.strip_kind, start, end) {
                         (StripKind::Prefix, Some(start), None) => {
@@ -235,7 +235,7 @@ fn find_stripping<'tcx>(
                                 if let ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, left, right) = end.kind;
                                 if let Some(left_arg) = len_arg(self.cx, left);
                                 if let ExprKind::Path(left_path) = &left_arg.kind;
-                                if qpath_res(self.cx, left_path, left_arg.hir_id) == self.target;
+                                if self.cx.qpath_res(left_path, left_arg.hir_id) == self.target;
                                 if eq_pattern_length(self.cx, self.pattern, right);
                                 then {
                                     self.results.push(ex.span);
diff --git a/src/tools/clippy/clippy_lints/src/mem_forget.rs b/src/tools/clippy/clippy_lints/src/mem_forget.rs
index 8c6fd10f98a..d34f9761e26 100644
--- a/src/tools/clippy/clippy_lints/src/mem_forget.rs
+++ b/src/tools/clippy/clippy_lints/src/mem_forget.rs
@@ -1,4 +1,4 @@
-use crate::utils::{match_def_path, paths, qpath_res, span_lint};
+use crate::utils::{match_def_path, paths, span_lint};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -29,7 +29,7 @@ impl<'tcx> LateLintPass<'tcx> for MemForget {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
         if let ExprKind::Call(ref path_expr, ref args) = e.kind {
             if let ExprKind::Path(ref qpath) = path_expr.kind {
-                if let Some(def_id) = qpath_res(cx, qpath, path_expr.hir_id).opt_def_id() {
+                if let Some(def_id) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id() {
                     if match_def_path(cx, def_id, &paths::MEM_FORGET) {
                         let forgot_ty = cx.typeck_results().expr_ty(&args[0]);
 
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index b1b5b3439a0..69302d695ce 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -1,4 +1,4 @@
-use crate::utils::{has_drop, qpath_res, snippet_opt, span_lint, span_lint_and_sugg};
+use crate::utils::{has_drop, snippet_opt, span_lint, span_lint_and_sugg};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{BinOpKind, BlockCheckMode, Expr, ExprKind, Stmt, StmtKind, UnsafeSource};
@@ -67,7 +67,7 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
         },
         ExprKind::Call(ref callee, ref args) => {
             if let ExprKind::Path(ref qpath) = callee.kind {
-                let res = qpath_res(cx, qpath, callee.hir_id);
+                let res = cx.qpath_res(qpath, callee.hir_id);
                 match res {
                     Res::Def(DefKind::Struct | DefKind::Variant | DefKind::Ctor(..), ..) => {
                         !has_drop(cx, cx.typeck_results().expr_ty(expr))
@@ -146,7 +146,7 @@ fn reduce_expression<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<Vec
         },
         ExprKind::Call(ref callee, ref args) => {
             if let ExprKind::Path(ref qpath) = callee.kind {
-                let res = qpath_res(cx, qpath, callee.hir_id);
+                let res = cx.qpath_res(qpath, callee.hir_id);
                 match res {
                     Res::Def(DefKind::Struct | DefKind::Variant | DefKind::Ctor(..), ..)
                         if !has_drop(cx, cx.typeck_results().expr_ty(expr)) =>
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index 3a9aa6ced03..f57d7536317 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -18,7 +18,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::{InnerSpan, Span, DUMMY_SP};
 use rustc_typeck::hir_ty_to_ty;
 
-use crate::utils::{in_constant, qpath_res, span_lint_and_then};
+use crate::utils::{in_constant, span_lint_and_then};
 use if_chain::if_chain;
 
 // FIXME: this is a correctness problem but there's no suitable
@@ -339,7 +339,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
             }
 
             // Make sure it is a const item.
-            let item_def_id = match qpath_res(cx, qpath, expr.hir_id) {
+            let item_def_id = match cx.qpath_res(qpath, expr.hir_id) {
                 Res::Def(DefKind::Const | DefKind::AssocConst, did) => did,
                 _ => return,
             };
diff --git a/src/tools/clippy/clippy_lints/src/to_string_in_display.rs b/src/tools/clippy/clippy_lints/src/to_string_in_display.rs
index c53727ba160..fa508df865e 100644
--- a/src/tools/clippy/clippy_lints/src/to_string_in_display.rs
+++ b/src/tools/clippy/clippy_lints/src/to_string_in_display.rs
@@ -1,4 +1,4 @@
-use crate::utils::{match_def_path, match_trait_method, paths, qpath_res, span_lint};
+use crate::utils::{match_def_path, match_trait_method, paths, span_lint};
 use if_chain::if_chain;
 use rustc_hir::def::Res;
 use rustc_hir::{Expr, ExprKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind};
@@ -94,7 +94,7 @@ impl LateLintPass<'_> for ToStringInDisplay {
             if match_trait_method(cx, expr, &paths::TO_STRING);
             if self.in_display_impl;
             if let ExprKind::Path(ref qpath) = args[0].kind;
-            if let Res::Local(hir_id) = qpath_res(cx, qpath, args[0].hir_id);
+            if let Res::Local(hir_id) = cx.qpath_res(qpath, args[0].hir_id);
             if let Some(self_hir_id) = self.self_hir_id;
             if hir_id == self_hir_id;
             then {
diff --git a/src/tools/clippy/clippy_lints/src/types.rs b/src/tools/clippy/clippy_lints/src/types.rs
index 17cef0af3e9..04c32ce9e8f 100644
--- a/src/tools/clippy/clippy_lints/src/types.rs
+++ b/src/tools/clippy/clippy_lints/src/types.rs
@@ -34,7 +34,7 @@ use crate::utils::sugg::Sugg;
 use crate::utils::{
     clip, comparisons, differing_macro_contexts, higher, in_constant, indent_of, int_bits, is_hir_ty_cfg_dependant,
     is_type_diagnostic_item, last_path_segment, match_def_path, match_path, meets_msrv, method_chain_args,
-    multispan_sugg, numeric_literal::NumericLiteral, qpath_res, reindent_multiline, sext, snippet, snippet_opt,
+    multispan_sugg, numeric_literal::NumericLiteral, reindent_multiline, sext, snippet, snippet_opt,
     snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg,
     span_lint_and_then, unsext,
 };
@@ -298,7 +298,7 @@ fn match_type_parameter(cx: &LateContext<'_>, qpath: &QPath<'_>, path: &[&str])
             _ => None,
         });
         if let TyKind::Path(ref qpath) = ty.kind;
-        if let Some(did) = qpath_res(cx, qpath, ty.hir_id).opt_def_id();
+        if let Some(did) = cx.qpath_res(qpath, ty.hir_id).opt_def_id();
         if match_def_path(cx, did, path);
         then {
             return Some(ty.span);
@@ -365,7 +365,7 @@ impl Types {
         match hir_ty.kind {
             TyKind::Path(ref qpath) if !is_local => {
                 let hir_id = hir_ty.hir_id;
-                let res = qpath_res(cx, qpath, hir_id);
+                let res = cx.qpath_res(qpath, hir_id);
                 if let Some(def_id) = res.opt_def_id() {
                     if Some(def_id) == cx.tcx.lang_items().owned_box() {
                         if let Some(span) = match_borrows_parameter(cx, qpath) {
@@ -535,7 +535,7 @@ impl Types {
                             });
                             // ty is now _ at this point
                             if let TyKind::Path(ref ty_qpath) = ty.kind;
-                            let res = qpath_res(cx, ty_qpath, ty.hir_id);
+                            let res = cx.qpath_res(ty_qpath, ty.hir_id);
                             if let Some(def_id) = res.opt_def_id();
                             if Some(def_id) == cx.tcx.lang_items().owned_box();
                             // At this point, we know ty is Box<T>, now get T
@@ -652,7 +652,7 @@ impl Types {
         match mut_ty.ty.kind {
             TyKind::Path(ref qpath) => {
                 let hir_id = mut_ty.ty.hir_id;
-                let def = qpath_res(cx, qpath, hir_id);
+                let def = cx.qpath_res(qpath, hir_id);
                 if_chain! {
                     if let Some(def_id) = def.opt_def_id();
                     if Some(def_id) == cx.tcx.lang_items().owned_box();
@@ -739,7 +739,7 @@ fn is_any_trait(t: &hir::Ty<'_>) -> bool {
 
 fn get_bounds_if_impl_trait<'tcx>(cx: &LateContext<'tcx>, qpath: &QPath<'_>, id: HirId) -> Option<GenericBounds<'tcx>> {
     if_chain! {
-        if let Some(did) = qpath_res(cx, qpath, id).opt_def_id();
+        if let Some(did) = cx.qpath_res(qpath, id).opt_def_id();
         if let Some(Node::GenericParam(generic_param)) = cx.tcx.hir().get_if_local(did);
         if let GenericParamKind::Type { synthetic, .. } = generic_param.kind;
         if synthetic == Some(SyntheticTyParamKind::ImplTrait);
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
index 7aa17520ba7..822863ca3e2 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
@@ -1,7 +1,7 @@
 use crate::consts::{constant_simple, Constant};
 use crate::utils::{
-    is_expn_of, match_def_path, match_qpath, match_type, method_calls, path_to_res, paths, qpath_res, run_lints,
-    snippet, span_lint, span_lint_and_help, span_lint_and_sugg, SpanlessEq,
+    is_expn_of, match_def_path, match_qpath, match_type, method_calls, path_to_res, paths, run_lints, snippet,
+    span_lint, span_lint_and_help, span_lint_and_sugg, SpanlessEq,
 };
 use if_chain::if_chain;
 use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, NodeId};
@@ -787,7 +787,7 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Ve
 
     match &expr.kind {
         ExprKind::AddrOf(.., expr) => return path_to_matched_type(cx, expr),
-        ExprKind::Path(qpath) => match qpath_res(cx, qpath, expr.hir_id) {
+        ExprKind::Path(qpath) => match cx.qpath_res(qpath, expr.hir_id) {
             Res::Local(hir_id) => {
                 let parent_id = cx.tcx.hir().get_parent_node(hir_id);
                 if let Some(Node::Local(local)) = cx.tcx.hir().find(parent_id) {
diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs
index 46b2b06d1a2..0bbb6a52a20 100644
--- a/src/tools/clippy/clippy_lints/src/utils/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs
@@ -369,19 +369,6 @@ pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Option<def::Res> {
     }
 }
 
-pub fn qpath_res(cx: &LateContext<'_>, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
-    match qpath {
-        hir::QPath::Resolved(_, path) => path.res,
-        hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => {
-            if cx.tcx.has_typeck_results(id.owner.to_def_id()) {
-                cx.tcx.typeck(id.owner).qpath_res(qpath, id)
-            } else {
-                Res::Err
-            }
-        },
-    }
-}
-
 /// Convenience function to get the `DefId` of a trait by path.
 /// It could be a trait or trait alias.
 pub fn get_trait_def_id(cx: &LateContext<'_>, path: &[&str]) -> Option<DefId> {
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 5608ff98417..52aed57fc76 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -2015,10 +2015,10 @@ impl<'test> TestCx<'test> {
                 rustc.args(&["-Zchalk"]);
             }
             Some(CompareMode::SplitDwarf) => {
-                rustc.args(&["-Zsplit-dwarf=split"]);
+                rustc.args(&["-Csplit-debuginfo=unpacked", "-Zunstable-options"]);
             }
             Some(CompareMode::SplitDwarfSingle) => {
-                rustc.args(&["-Zsplit-dwarf=single"]);
+                rustc.args(&["-Csplit-debuginfo=packed", "-Zunstable-options"]);
             }
             None => {}
         }
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index e687901f212..21d05226fb4 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -7,7 +7,7 @@ use std::path::Path;
 
 const ENTRY_LIMIT: usize = 1000;
 // FIXME: The following limits should be reduced eventually.
-const ROOT_ENTRY_LIMIT: usize = 1458;
+const ROOT_ENTRY_LIMIT: usize = 1459;
 const ISSUES_ENTRY_LIMIT: usize = 2669;
 
 fn check_entries(path: &Path, bad: &mut bool) {