Rollup merge of #67274 - RalfJung:uninit, r=Centril

be explicit that mem::uninitialized is the same as MaybeUninit::uninit().assume_init()

Cc @Centril @nikomatsakis
diff --git a/Cargo.lock b/Cargo.lock
index 07a6c53..fc4e3bc 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3435,7 +3435,27 @@
 name = "rustc_codegen_llvm"
 version = "0.0.0"
 dependencies = [
+ "bitflags",
+ "flate2",
+ "libc",
+ "log",
+ "rustc",
+ "rustc-demangle",
+ "rustc_codegen_ssa",
+ "rustc_codegen_utils",
+ "rustc_data_structures",
+ "rustc_errors",
+ "rustc_feature",
+ "rustc_fs_util",
+ "rustc_incremental",
+ "rustc_index",
  "rustc_llvm",
+ "rustc_session",
+ "rustc_target",
+ "smallvec 0.6.10",
+ "syntax",
+ "syntax_expand",
+ "syntax_pos",
 ]
 
 [[package]]
@@ -3597,6 +3617,7 @@
  "once_cell",
  "rustc",
  "rustc-rayon",
+ "rustc_codegen_llvm",
  "rustc_codegen_ssa",
  "rustc_codegen_utils",
  "rustc_data_structures",
@@ -3651,6 +3672,7 @@
 dependencies = [
  "build_helper",
  "cc",
+ "libc",
 ]
 
 [[package]]
diff --git a/config.toml.example b/config.toml.example
index e832570..5152a6c 100644
--- a/config.toml.example
+++ b/config.toml.example
@@ -379,9 +379,6 @@
 # and currently the only standard option supported is `"llvm"`
 #codegen-backends = ["llvm"]
 
-# This is the name of the directory in which codegen backends will get installed
-#codegen-backends-dir = "codegen-backends"
-
 # Indicates whether LLD will be compiled and made available in the sysroot for
 # rustc to execute.
 #lld = false
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index fc1e1cf..8b0ad16 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -339,7 +339,6 @@
             Kind::Build => describe!(
                 compile::Std,
                 compile::Rustc,
-                compile::CodegenBackend,
                 compile::StartupObjects,
                 tool::BuildManifest,
                 tool::Rustbook,
@@ -364,7 +363,6 @@
             Kind::Check | Kind::Clippy | Kind::Fix => describe!(
                 check::Std,
                 check::Rustc,
-                check::CodegenBackend,
                 check::Rustdoc
             ),
             Kind::Test => describe!(
@@ -632,11 +630,6 @@
         self.ensure(Libdir { compiler, target })
     }
 
-    pub fn sysroot_codegen_backends(&self, compiler: Compiler) -> PathBuf {
-        self.sysroot_libdir(compiler, compiler.host)
-            .with_file_name(self.config.rust_codegen_backends_dir.clone())
-    }
-
     /// Returns the compiler's libdir where it stores the dynamic libraries that
     /// it itself links against.
     ///
@@ -707,15 +700,6 @@
         }
     }
 
-    /// Gets the paths to all of the compiler's codegen backends.
-    fn codegen_backends(&self, compiler: Compiler) -> impl Iterator<Item = PathBuf> {
-        fs::read_dir(self.sysroot_codegen_backends(compiler))
-            .into_iter()
-            .flatten()
-            .filter_map(Result::ok)
-            .map(|entry| entry.path())
-    }
-
     pub fn rustdoc(&self, compiler: Compiler) -> PathBuf {
         self.ensure(tool::Rustdoc { compiler })
     }
@@ -759,12 +743,6 @@
         let mut cargo = Command::new(&self.initial_cargo);
         let out_dir = self.stage_out(compiler, mode);
 
-        // Codegen backends are not yet tracked by -Zbinary-dep-depinfo,
-        // so we need to explicitly clear out if they've been updated.
-        for backend in self.codegen_backends(compiler) {
-            self.clear_if_dirty(&out_dir, &backend);
-        }
-
         if cmd == "doc" || cmd == "rustdoc" {
             let my_out = match mode {
                 // This is the intended out directory for compiler documentation.
diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs
index 2bb90fd..b9d97fb 100644
--- a/src/bootstrap/builder/tests.rs
+++ b/src/bootstrap/builder/tests.rs
@@ -363,6 +363,10 @@
                 compiler: Compiler { host: a, stage: 1 },
                 target: b,
             },
+            compile::Std {
+                compiler: Compiler { host: a, stage: 2 },
+                target: b,
+            },
         ]
     );
     assert_eq!(
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index df1c725..f5c427d 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -1,11 +1,10 @@
 //! Implementation of compiling the compiler and standard library, in "check"-based modes.
 
-use crate::compile::{run_cargo, std_cargo, rustc_cargo, rustc_cargo_env,
-                     add_to_sysroot};
+use crate::compile::{run_cargo, std_cargo, rustc_cargo, add_to_sysroot};
 use crate::builder::{RunConfig, Builder, Kind, ShouldRun, Step};
 use crate::tool::{prepare_tool_cargo, SourceType};
 use crate::{Compiler, Mode};
-use crate::cache::{INTERNER, Interned};
+use crate::cache::Interned;
 use std::path::PathBuf;
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@@ -97,7 +96,7 @@
 
         let mut cargo = builder.cargo(compiler, Mode::Rustc, target,
             cargo_subcommand(builder.kind));
-        rustc_cargo(builder, &mut cargo);
+        rustc_cargo(builder, &mut cargo, target);
 
         builder.info(&format!("Checking compiler artifacts ({} -> {})", &compiler.host, target));
         run_cargo(builder,
@@ -114,55 +113,6 @@
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub struct CodegenBackend {
-    pub target: Interned<String>,
-    pub backend: Interned<String>,
-}
-
-impl Step for CodegenBackend {
-    type Output = ();
-    const ONLY_HOSTS: bool = true;
-    const DEFAULT: bool = true;
-
-    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.all_krates("rustc_codegen_llvm")
-    }
-
-    fn make_run(run: RunConfig<'_>) {
-        let backend = run.builder.config.rust_codegen_backends.get(0);
-        let backend = backend.cloned().unwrap_or_else(|| {
-            INTERNER.intern_str("llvm")
-        });
-        run.builder.ensure(CodegenBackend {
-            target: run.target,
-            backend,
-        });
-    }
-
-    fn run(self, builder: &Builder<'_>) {
-        let compiler = builder.compiler(0, builder.config.build);
-        let target = self.target;
-        let backend = self.backend;
-
-        builder.ensure(Rustc { target });
-
-        let mut cargo = builder.cargo(compiler, Mode::Codegen, target,
-            cargo_subcommand(builder.kind));
-        cargo.arg("--manifest-path").arg(builder.src.join("src/librustc_codegen_llvm/Cargo.toml"));
-        rustc_cargo_env(builder, &mut cargo);
-
-        // We won't build LLVM if it's not available, as it shouldn't affect `check`.
-
-        run_cargo(builder,
-                  cargo,
-                  args(builder.kind),
-                  &codegen_backend_stamp(builder, compiler, target, backend),
-                  vec![],
-                  true);
-    }
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Rustdoc {
     pub target: Interned<String>,
 }
@@ -231,16 +181,6 @@
     builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc-check.stamp")
 }
 
-/// Cargo's output path for librustc_codegen_llvm in a given stage, compiled by a particular
-/// compiler for the specified target and backend.
-fn codegen_backend_stamp(builder: &Builder<'_>,
-                         compiler: Compiler,
-                         target: Interned<String>,
-                         backend: Interned<String>) -> PathBuf {
-    builder.cargo_out(compiler, Mode::Codegen, target)
-         .join(format!(".librustc_codegen_llvm-{}-check.stamp", backend))
-}
-
 /// Cargo's output path for rustdoc in a given stage, compiled by a particular
 /// compiler for the specified target.
 pub fn rustdoc_stamp(
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index f686dfe..baf9aab 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -27,7 +27,7 @@
 use crate::native;
 
 use crate::cache::{INTERNER, Interned};
-use crate::builder::{Step, RunConfig, ShouldRun, Builder};
+use crate::builder::{Step, RunConfig, ShouldRun, Builder, Kind};
 
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Std {
@@ -445,7 +445,7 @@
         });
 
         let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "build");
-        rustc_cargo(builder, &mut cargo);
+        rustc_cargo(builder, &mut cargo, target);
 
         builder.info(&format!("Building stage{} compiler artifacts ({} -> {})",
                  compiler.stage, &compiler.host, target));
@@ -456,6 +456,44 @@
                   vec![],
                   false);
 
+        // We used to build librustc_codegen_llvm as a separate step,
+        // which produced a dylib that the compiler would dlopen() at runtime.
+        // This meant that we only needed to make sure that libLLVM.so was
+        // installed by the time we went to run a tool using it - since
+        // librustc_codegen_llvm was effectively a standalone artifact,
+        // other crates were completely oblivious to its dependency
+        // on `libLLVM.so` during build time.
+        //
+        // However, librustc_codegen_llvm is now built as an ordinary
+        // crate during the same step as the rest of the compiler crates.
+        // This means that any crates depending on it will see the fact
+        // that it uses `libLLVM.so` as a native library, and will
+        // cause us to pass `-llibLLVM.so` to the linker when we link
+        // a binary.
+        //
+        // For `rustc` itself, this works out fine.
+        // During the `Assemble` step, we call `dist::maybe_install_llvm_dylib`
+        // to copy libLLVM.so into the `stage` directory. We then link
+        // the compiler binary, which will find `libLLVM.so` in the correct place.
+        //
+        // However, this is insufficient for tools that are build against stage0
+        // (e.g. stage1 rustdoc). Since `Assemble` for stage0 doesn't actually do anything,
+        // we won't have `libLLVM.so` in the stage0 sysroot. In the past, this wasn't
+        // a problem - we would copy the tool binary into its correct stage directory
+        // (e.g. stage1 for a stage1 rustdoc built against a stage0 compiler).
+        // Since libLLVM.so wasn't resolved until runtime, it was fine for it to
+        // not exist while we were building it.
+        //
+        // To ensure that we can still build stage1 tools against a stage0 compiler,
+        // we explicitly copy libLLVM.so into the stage0 sysroot when building
+        // the stage0 compiler. This ensures that tools built against stage0
+        // will see libLLVM.so at build time, making the linker happy.
+        if compiler.stage == 0 {
+            builder.info(&format!("Installing libLLVM.so to stage 0 ({})", compiler.host));
+            let sysroot = builder.sysroot(compiler);
+            dist::maybe_install_llvm_dylib(builder, compiler.host, &sysroot);
+        }
+
         builder.ensure(RustcLink {
             compiler: builder.compiler(compiler.stage, builder.config.build),
             target_compiler: compiler,
@@ -464,21 +502,20 @@
     }
 }
 
-pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo) {
+pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo, target: Interned<String>) {
     cargo.arg("--features").arg(builder.rustc_features())
          .arg("--manifest-path")
          .arg(builder.src.join("src/rustc/Cargo.toml"));
-    rustc_cargo_env(builder, cargo);
+    rustc_cargo_env(builder, cargo, target);
 }
 
-pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo) {
+pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: Interned<String>) {
     // Set some configuration variables picked up by build scripts and
     // the compiler alike
     cargo.env("CFG_RELEASE", builder.rust_release())
          .env("CFG_RELEASE_CHANNEL", &builder.config.channel)
          .env("CFG_VERSION", builder.rust_version())
-         .env("CFG_PREFIX", builder.config.prefix.clone().unwrap_or_default())
-         .env("CFG_CODEGEN_BACKENDS_DIR", &builder.config.rust_codegen_backends_dir);
+         .env("CFG_PREFIX", builder.config.prefix.clone().unwrap_or_default());
 
     let libdir_relative = builder.config.libdir_relative().unwrap_or(Path::new("lib"));
     cargo.env("CFG_LIBDIR_RELATIVE", libdir_relative);
@@ -501,6 +538,49 @@
     if builder.config.rust_verify_llvm_ir {
         cargo.env("RUSTC_VERIFY_LLVM_IR", "1");
     }
+
+    // Pass down configuration from the LLVM build into the build of
+    // librustc_llvm and librustc_codegen_llvm.
+    //
+    // Note that this is disabled if LLVM itself is disabled or we're in a check
+    // build, where if we're in a check build there's no need to build all of
+    // LLVM and such.
+    if builder.config.llvm_enabled() && builder.kind != Kind::Check {
+        if builder.is_rust_llvm(target) {
+            cargo.env("LLVM_RUSTLLVM", "1");
+        }
+        let llvm_config = builder.ensure(native::Llvm { target });
+        cargo.env("LLVM_CONFIG", &llvm_config);
+        let target_config = builder.config.target_config.get(&target);
+        if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
+            cargo.env("CFG_LLVM_ROOT", s);
+        }
+        // Some LLVM linker flags (-L and -l) may be needed to link librustc_llvm.
+        if let Some(ref s) = builder.config.llvm_ldflags {
+            cargo.env("LLVM_LINKER_FLAGS", s);
+        }
+        // Building with a static libstdc++ is only supported on linux right now,
+        // not for MSVC or macOS
+        if builder.config.llvm_static_stdcpp &&
+           !target.contains("freebsd") &&
+           !target.contains("windows") &&
+           !target.contains("apple") {
+            let file = compiler_file(builder,
+                                     builder.cxx(target).unwrap(),
+                                     target,
+                                     "libstdc++.a");
+            cargo.env("LLVM_STATIC_STDCPP", file);
+        }
+        if builder.config.llvm_link_shared || builder.config.llvm_thin_lto {
+            cargo.env("LLVM_LINK_SHARED", "1");
+        }
+        if builder.config.llvm_use_libcxx {
+            cargo.env("LLVM_USE_LIBCXX", "1");
+        }
+        if builder.config.llvm_optimize && !builder.config.llvm_release_debuginfo {
+            cargo.env("LLVM_NDEBUG", "1");
+        }
+    }
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@@ -537,215 +617,6 @@
     }
 }
 
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub struct CodegenBackend {
-    pub compiler: Compiler,
-    pub target: Interned<String>,
-    pub backend: Interned<String>,
-}
-
-impl Step for CodegenBackend {
-    type Output = ();
-    const ONLY_HOSTS: bool = true;
-    const DEFAULT: bool = true;
-
-    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.all_krates("rustc_codegen_llvm")
-    }
-
-    fn make_run(run: RunConfig<'_>) {
-        let backend = run.builder.config.rust_codegen_backends.get(0);
-        let backend = backend.cloned().unwrap_or_else(|| {
-            INTERNER.intern_str("llvm")
-        });
-        run.builder.ensure(CodegenBackend {
-            compiler: run.builder.compiler(run.builder.top_stage, run.host),
-            target: run.target,
-            backend,
-        });
-    }
-
-    fn run(self, builder: &Builder<'_>) {
-        let compiler = self.compiler;
-        let target = self.target;
-        let backend = self.backend;
-
-        builder.ensure(Rustc { compiler, target });
-
-        if builder.config.keep_stage.contains(&compiler.stage) {
-            builder.info("Warning: Using a potentially old codegen backend. \
-                This may not behave well.");
-            // Codegen backends are linked separately from this step today, so we don't do
-            // anything here.
-            return;
-        }
-
-        let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
-        if compiler_to_use != compiler {
-            builder.ensure(CodegenBackend {
-                compiler: compiler_to_use,
-                target,
-                backend,
-            });
-            return;
-        }
-
-        let out_dir = builder.cargo_out(compiler, Mode::Codegen, target);
-
-        let mut cargo = builder.cargo(compiler, Mode::Codegen, target, "build");
-        cargo.arg("--manifest-path")
-            .arg(builder.src.join("src/librustc_codegen_llvm/Cargo.toml"));
-        rustc_cargo_env(builder, &mut cargo);
-
-        let features = build_codegen_backend(&builder, &mut cargo, &compiler, target, backend);
-        cargo.arg("--features").arg(features);
-
-        let tmp_stamp = out_dir.join(".tmp.stamp");
-
-        let files = run_cargo(builder, cargo, vec![], &tmp_stamp, vec![], false);
-        if builder.config.dry_run {
-            return;
-        }
-        let mut files = files.into_iter()
-            .filter(|f| {
-                let filename = f.file_name().unwrap().to_str().unwrap();
-                is_dylib(filename) && filename.contains("rustc_codegen_llvm-")
-            });
-        let codegen_backend = match files.next() {
-            Some(f) => f,
-            None => panic!("no dylibs built for codegen backend?"),
-        };
-        if let Some(f) = files.next() {
-            panic!("codegen backend built two dylibs:\n{}\n{}",
-                   codegen_backend.display(),
-                   f.display());
-        }
-        let stamp = codegen_backend_stamp(builder, compiler, target, backend);
-        let codegen_backend = codegen_backend.to_str().unwrap();
-        t!(fs::write(&stamp, &codegen_backend));
-    }
-}
-
-pub fn build_codegen_backend(builder: &Builder<'_>,
-                             cargo: &mut Cargo,
-                             compiler: &Compiler,
-                             target: Interned<String>,
-                             backend: Interned<String>) -> String {
-    match &*backend {
-        "llvm" => {
-            // Build LLVM for our target. This will implicitly build the
-            // host LLVM if necessary.
-            let llvm_config = builder.ensure(native::Llvm {
-                target,
-            });
-
-            builder.info(&format!("Building stage{} codegen artifacts ({} -> {}, {})",
-                     compiler.stage, &compiler.host, target, backend));
-
-            // Pass down configuration from the LLVM build into the build of
-            // librustc_llvm and librustc_codegen_llvm.
-            if builder.is_rust_llvm(target) {
-                cargo.env("LLVM_RUSTLLVM", "1");
-            }
-
-            cargo.env("LLVM_CONFIG", &llvm_config);
-            let target_config = builder.config.target_config.get(&target);
-            if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
-                cargo.env("CFG_LLVM_ROOT", s);
-            }
-            // Some LLVM linker flags (-L and -l) may be needed to link librustc_llvm.
-            if let Some(ref s) = builder.config.llvm_ldflags {
-                cargo.env("LLVM_LINKER_FLAGS", s);
-            }
-            // Building with a static libstdc++ is only supported on linux and mingw right now,
-            // not for MSVC or macOS
-            if builder.config.llvm_static_stdcpp &&
-               !target.contains("freebsd") &&
-               !target.contains("msvc") &&
-               !target.contains("apple") {
-                let file = compiler_file(builder,
-                                         builder.cxx(target).unwrap(),
-                                         target,
-                                         "libstdc++.a");
-                cargo.env("LLVM_STATIC_STDCPP", file);
-            }
-            if builder.config.llvm_link_shared || builder.config.llvm_thin_lto {
-                cargo.env("LLVM_LINK_SHARED", "1");
-            }
-            if builder.config.llvm_use_libcxx {
-                cargo.env("LLVM_USE_LIBCXX", "1");
-            }
-            if builder.config.llvm_optimize && !builder.config.llvm_release_debuginfo {
-                cargo.env("LLVM_NDEBUG", "1");
-            }
-        }
-        _ => panic!("unknown backend: {}", backend),
-    }
-    String::new()
-}
-
-/// Creates the `codegen-backends` folder for a compiler that's about to be
-/// assembled as a complete compiler.
-///
-/// This will take the codegen artifacts produced by `compiler` and link them
-/// into an appropriate location for `target_compiler` to be a functional
-/// compiler.
-fn copy_codegen_backends_to_sysroot(builder: &Builder<'_>,
-                                    compiler: Compiler,
-                                    target_compiler: Compiler) {
-    let target = target_compiler.host;
-
-    // Note that this step is different than all the other `*Link` steps in
-    // that it's not assembling a bunch of libraries but rather is primarily
-    // moving the codegen backend into place. The codegen backend of rustc is
-    // not linked into the main compiler by default but is rather dynamically
-    // selected at runtime for inclusion.
-    //
-    // Here we're looking for the output dylib of the `CodegenBackend` step and
-    // we're copying that into the `codegen-backends` folder.
-    let dst = builder.sysroot_codegen_backends(target_compiler);
-    t!(fs::create_dir_all(&dst));
-
-    if builder.config.dry_run {
-        return;
-    }
-
-    for backend in builder.config.rust_codegen_backends.iter() {
-        let stamp = codegen_backend_stamp(builder, compiler, target, *backend);
-        let dylib = t!(fs::read_to_string(&stamp));
-        let file = Path::new(&dylib);
-        let filename = file.file_name().unwrap().to_str().unwrap();
-        // change `librustc_codegen_llvm-xxxxxx.so` to `librustc_codegen_llvm-llvm.so`
-        let target_filename = {
-            let dash = filename.find('-').unwrap();
-            let dot = filename.find('.').unwrap();
-            format!("{}-{}{}",
-                    &filename[..dash],
-                    backend,
-                    &filename[dot..])
-        };
-        builder.copy(&file, &dst.join(target_filename));
-    }
-}
-
-fn copy_lld_to_sysroot(builder: &Builder<'_>,
-                       target_compiler: Compiler,
-                       lld_install_root: &Path) {
-    let target = target_compiler.host;
-
-    let dst = builder.sysroot_libdir(target_compiler, target)
-        .parent()
-        .unwrap()
-        .join("bin");
-    t!(fs::create_dir_all(&dst));
-
-    let src_exe = exe("lld", &target);
-    let dst_exe = exe("rust-lld", &target);
-    // we prepend this bin directory to the user PATH when linking Rust binaries. To
-    // avoid shadowing the system LLD we rename the LLD we provide to `rust-lld`.
-    builder.copy(&lld_install_root.join("bin").join(&src_exe), &dst.join(&dst_exe));
-}
-
 /// Cargo's output path for the standard library in a given stage, compiled
 /// by a particular compiler for the specified target.
 pub fn libstd_stamp(
@@ -766,16 +637,6 @@
     builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc.stamp")
 }
 
-/// Cargo's output path for librustc_codegen_llvm in a given stage, compiled by a particular
-/// compiler for the specified target and backend.
-fn codegen_backend_stamp(builder: &Builder<'_>,
-                         compiler: Compiler,
-                         target: Interned<String>,
-                         backend: Interned<String>) -> PathBuf {
-    builder.cargo_out(compiler, Mode::Codegen, target)
-        .join(format!(".librustc_codegen_llvm-{}.stamp", backend))
-}
-
 pub fn compiler_file(
     builder: &Builder<'_>,
     compiler: &Path,
@@ -879,13 +740,6 @@
             compiler: build_compiler,
             target: target_compiler.host,
         });
-        for &backend in builder.config.rust_codegen_backends.iter() {
-            builder.ensure(CodegenBackend {
-                compiler: build_compiler,
-                target: target_compiler.host,
-                backend,
-            });
-        }
 
         let lld_install = if builder.config.lld_enabled {
             Some(builder.ensure(native::Lld {
@@ -911,13 +765,19 @@
             }
         }
 
-        copy_codegen_backends_to_sysroot(builder,
-                                         build_compiler,
-                                         target_compiler);
+        let libdir = builder.sysroot_libdir(target_compiler, target_compiler.host);
         if let Some(lld_install) = lld_install {
-            copy_lld_to_sysroot(builder, target_compiler, &lld_install);
+            let src_exe = exe("lld", &target_compiler.host);
+            let dst_exe = exe("rust-lld", &target_compiler.host);
+            // we prepend this bin directory to the user PATH when linking Rust binaries. To
+            // avoid shadowing the system LLD we rename the LLD we provide to `rust-lld`.
+            let dst = libdir.parent().unwrap().join("bin");
+            t!(fs::create_dir_all(&dst));
+            builder.copy(&lld_install.join("bin").join(&src_exe), &dst.join(&dst_exe));
         }
 
+        // Ensure that `libLLVM.so` ends up in the newly build compiler directory,
+        // so that it can be found when the newly built `rustc` is run.
         dist::maybe_install_llvm_dylib(builder, target_compiler.host, &sysroot);
 
         // Link the compiler binary itself into place
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 0c03b95..5f2ef01 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -105,7 +105,6 @@
     pub rust_optimize_tests: bool,
     pub rust_dist_src: bool,
     pub rust_codegen_backends: Vec<Interned<String>>,
-    pub rust_codegen_backends_dir: String,
     pub rust_verify_llvm_ir: bool,
     pub rust_remap_debuginfo: bool,
 
@@ -316,7 +315,6 @@
     dist_src: Option<bool>,
     save_toolstates: Option<String>,
     codegen_backends: Option<Vec<String>>,
-    codegen_backends_dir: Option<String>,
     lld: Option<bool>,
     llvm_tools: Option<bool>,
     lldb: Option<bool>,
@@ -372,7 +370,6 @@
         config.ignore_git = false;
         config.rust_dist_src = true;
         config.rust_codegen_backends = vec![INTERNER.intern_str("llvm")];
-        config.rust_codegen_backends_dir = "codegen-backends".to_owned();
         config.deny_warnings = true;
         config.missing_tools = false;
 
@@ -575,8 +572,6 @@
                     .collect();
             }
 
-            set(&mut config.rust_codegen_backends_dir, rust.codegen_backends_dir.clone());
-
             config.rust_codegen_units = rust.codegen_units.map(threads_from_config);
             config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config);
         }
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index d0c9e0d..0253394 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -498,16 +498,6 @@
                 }
             }
 
-            // Copy over the codegen backends
-            let backends_src = builder.sysroot_codegen_backends(compiler);
-            let backends_rel = backends_src.strip_prefix(&src).unwrap()
-                .strip_prefix(builder.sysroot_libdir_relative(compiler)).unwrap();
-            // Don't use custom libdir here because ^lib/ will be resolved again with installer
-            let backends_dst = image.join("lib").join(&backends_rel);
-
-            t!(fs::create_dir_all(&backends_dst));
-            builder.cp_r(&backends_src, &backends_dst);
-
             // Copy libLLVM.so to the lib dir as well, if needed. While not
             // technically needed by rustc itself it's needed by lots of other
             // components like the llvm tools and LLD. LLD is included below and
@@ -2134,6 +2124,10 @@
 
 // Maybe add libLLVM.so to the lib-dir. It will only have been built if
 // LLVM tools are linked dynamically.
+//
+// We add this to both the libdir of the rustc binary itself (for it to load at
+// runtime) and also to the target directory so it can find it at link-time.
+//
 // Note: This function does no yet support Windows but we also don't support
 //       linking LLVM tools dynamically on Windows yet.
 pub fn maybe_install_llvm_dylib(builder: &Builder<'_>,
@@ -2142,13 +2136,19 @@
     let src_libdir = builder
         .llvm_out(target)
         .join("lib");
-    let dst_libdir = sysroot.join("lib/rustlib").join(&*target).join("lib");
-    t!(fs::create_dir_all(&dst_libdir));
+    let dst_libdir1 = sysroot.join("lib/rustlib").join(&*target).join("lib");
+    let dst_libdir2 = sysroot.join(builder.sysroot_libdir_relative(Compiler {
+        stage: 1,
+        host: target,
+    }));
+    t!(fs::create_dir_all(&dst_libdir1));
+    t!(fs::create_dir_all(&dst_libdir2));
 
     if target.contains("apple-darwin") {
         let llvm_dylib_path = src_libdir.join("libLLVM.dylib");
         if llvm_dylib_path.exists() {
-            builder.install(&llvm_dylib_path, &dst_libdir, 0o644);
+            builder.install(&llvm_dylib_path, &dst_libdir1, 0o644);
+            builder.install(&llvm_dylib_path, &dst_libdir2, 0o644);
         }
         return
     }
@@ -2164,7 +2164,8 @@
         });
 
 
-        builder.install(&llvm_dylib_path, &dst_libdir, 0o644);
+        builder.install(&llvm_dylib_path, &dst_libdir1, 0o644);
+        builder.install(&llvm_dylib_path, &dst_libdir2, 0o644);
     }
 }
 
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index 4ee8cd2..608cee0 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -433,7 +433,7 @@
         builder.info(&format!("Documenting stage{} std ({})", stage, target));
         let out = builder.doc_out(target);
         t!(fs::create_dir_all(&out));
-        let compiler = builder.compiler_for(stage, builder.config.build, target);
+        let compiler = builder.compiler(stage, builder.config.build);
 
         builder.ensure(compile::Std { compiler, target });
         let out_dir = builder.stage_out(compiler, Mode::Std)
@@ -541,7 +541,7 @@
         // Build cargo command.
         let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "doc");
         cargo.env("RUSTDOCFLAGS", "--document-private-items --passes strip-hidden");
-        compile::rustc_cargo(builder, &mut cargo);
+        compile::rustc_cargo(builder, &mut cargo, target);
 
         // Only include compiler crates, no dependencies of those, such as `libc`.
         cargo.arg("--no-deps");
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 7f7e291..080bef6 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -500,6 +500,9 @@
         if self.config.jemalloc {
             features.push_str("jemalloc");
         }
+        if self.config.llvm_enabled() {
+            features.push_str(" llvm");
+        }
         features
     }
 
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index a858ed4..f3b2a73 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -1773,7 +1773,7 @@
             }
             Mode::Rustc => {
                 builder.ensure(compile::Rustc { compiler, target });
-                compile::rustc_cargo(builder, &mut cargo);
+                compile::rustc_cargo(builder, &mut cargo, target);
             }
             _ => panic!("can only test libraries"),
         };
diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs
index ebd3f01..9136136 100644
--- a/src/liballoc/collections/vec_deque.rs
+++ b/src/liballoc/collections/vec_deque.rs
@@ -144,11 +144,23 @@
 #[stable(feature = "rust1", since = "1.0.0")]
 unsafe impl<#[may_dangle] T> Drop for VecDeque<T> {
     fn drop(&mut self) {
+        /// Runs the destructor for all items in the slice when it gets dropped (normally or
+        /// during unwinding).
+        struct Dropper<'a, T>(&'a mut [T]);
+
+        impl<'a, T> Drop for Dropper<'a, T> {
+            fn drop(&mut self) {
+                unsafe {
+                    ptr::drop_in_place(self.0);
+                }
+            }
+        }
+
         let (front, back) = self.as_mut_slices();
         unsafe {
+            let _back_dropper = Dropper(back);
             // use drop for [T]
             ptr::drop_in_place(front);
-            ptr::drop_in_place(back);
         }
         // RawVec handles deallocation
     }
diff --git a/src/liballoc/tests/vec_deque.rs b/src/liballoc/tests/vec_deque.rs
index ebcc832..1ab3694 100644
--- a/src/liballoc/tests/vec_deque.rs
+++ b/src/liballoc/tests/vec_deque.rs
@@ -2,6 +2,7 @@
 use std::collections::{vec_deque::Drain, VecDeque};
 use std::fmt::Debug;
 use std::mem::size_of;
+use std::panic::catch_unwind;
 use std::{isize, usize};
 
 use crate::hash;
@@ -710,6 +711,39 @@
 }
 
 #[test]
+fn test_drop_panic() {
+    static mut DROPS: i32 = 0;
+
+    struct D(bool);
+
+    impl Drop for D {
+        fn drop(&mut self) {
+            unsafe {
+                DROPS += 1;
+            }
+
+            if self.0 {
+                panic!("panic in `drop`");
+            }
+        }
+    }
+
+    let mut q = VecDeque::new();
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_front(D(false));
+    q.push_front(D(false));
+    q.push_front(D(true));
+
+    catch_unwind(move || drop(q)).ok();
+
+    assert_eq!(unsafe { DROPS }, 8);
+}
+
+#[test]
 fn test_reserve_grow() {
     // test growth path A
     // [T o o H] -> [T o o H . . . . ]
diff --git a/src/librustc_codegen_llvm/Cargo.toml b/src/librustc_codegen_llvm/Cargo.toml
index 867bbd2..71cfacf 100644
--- a/src/librustc_codegen_llvm/Cargo.toml
+++ b/src/librustc_codegen_llvm/Cargo.toml
@@ -7,8 +7,28 @@
 [lib]
 name = "rustc_codegen_llvm"
 path = "lib.rs"
-crate-type = ["dylib"]
 test = false
+doctest = false
 
 [dependencies]
+bitflags = "1.0"
+flate2 = "1.0"
+libc = "0.2"
+log = "0.4"
+rustc = { path = "../librustc" }
+rustc-demangle = "0.1"
+rustc_codegen_ssa = { path = "../librustc_codegen_ssa" }
+rustc_codegen_utils = { path = "../librustc_codegen_utils" }
+rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_errors = { path = "../librustc_errors" }
+rustc_feature = { path = "../librustc_feature" }
+rustc_fs_util = { path = "../librustc_fs_util" }
+rustc_incremental = { path = "../librustc_incremental" }
+rustc_index = { path = "../librustc_index" }
 rustc_llvm = { path = "../librustc_llvm" }
+rustc_session = { path = "../librustc_session" }
+rustc_target = { path = "../librustc_target" }
+smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
+syntax = { path = "../libsyntax" }
+syntax_expand = { path = "../libsyntax_expand" }
+syntax_pos = { path = "../libsyntax_pos" }
diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs
index 1f3c8e1..2607a49 100644
--- a/src/librustc_codegen_llvm/abi.rs
+++ b/src/librustc_codegen_llvm/abi.rs
@@ -8,6 +8,7 @@
 use rustc_codegen_ssa::MemFlags;
 use rustc_codegen_ssa::mir::place::PlaceRef;
 use rustc_codegen_ssa::mir::operand::OperandValue;
+use rustc::bug;
 use rustc_codegen_ssa::traits::*;
 use rustc_target::abi::call::ArgAbi;
 use rustc_target::abi::{HasDataLayout, LayoutOf};
diff --git a/src/librustc_codegen_llvm/allocator.rs b/src/librustc_codegen_llvm/allocator.rs
index 11b6e0b..e1d56b9 100644
--- a/src/librustc_codegen_llvm/allocator.rs
+++ b/src/librustc_codegen_llvm/allocator.rs
@@ -4,6 +4,7 @@
 use libc::c_uint;
 use rustc::ty::TyCtxt;
 use syntax::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
+use rustc::bug;
 
 use crate::ModuleLlvm;
 use crate::llvm::{self, False, True};
diff --git a/src/librustc_codegen_llvm/asm.rs b/src/librustc_codegen_llvm/asm.rs
index abdd2e3..fa43e08 100644
--- a/src/librustc_codegen_llvm/asm.rs
+++ b/src/librustc_codegen_llvm/asm.rs
@@ -12,7 +12,7 @@
 
 use std::ffi::{CStr, CString};
 use libc::{c_uint, c_char};
-
+use log::debug;
 
 impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
     fn codegen_inline_asm(
diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs
index 1ea9362..5479a1f 100644
--- a/src/librustc_codegen_llvm/attributes.rs
+++ b/src/librustc_codegen_llvm/attributes.rs
@@ -12,6 +12,7 @@
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_target::abi::call::Conv;
+use rustc_data_structures::const_cstr;
 use rustc_target::spec::PanicStrategy;
 use rustc_codegen_ssa::traits::*;
 
diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs
index 858dd59..0e4e4e2 100644
--- a/src/librustc_codegen_llvm/back/lto.rs
+++ b/src/librustc_codegen_llvm/back/lto.rs
@@ -4,11 +4,12 @@
 use crate::llvm::archive_ro::ArchiveRO;
 use crate::llvm::{self, True, False};
 use crate::{ModuleLlvm, LlvmCodegenBackend};
+use rustc::bug;
 use rustc_codegen_ssa::back::symbol_export;
 use rustc_codegen_ssa::back::write::{ModuleConfig, CodegenContext, FatLTOInput};
 use rustc_codegen_ssa::back::lto::{SerializedModule, LtoModuleCodegen, ThinShared, ThinModule};
 use rustc_codegen_ssa::traits::*;
-use errors::{FatalError, Handler};
+use rustc_errors::{FatalError, Handler};
 use rustc::dep_graph::WorkProduct;
 use rustc_session::cgu_reuse_tracker::CguReuse;
 use rustc::hir::def_id::LOCAL_CRATE;
@@ -17,6 +18,7 @@
 use rustc::util::common::time_ext;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_codegen_ssa::{RLIB_BYTECODE_EXTENSION, ModuleCodegen, ModuleKind};
+use log::{info, debug};
 
 use std::ffi::{CStr, CString};
 use std::ptr;
diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs
index ada29c3..796ea7a 100644
--- a/src/librustc_codegen_llvm/back/write.rs
+++ b/src/librustc_codegen_llvm/back/write.rs
@@ -10,6 +10,7 @@
 use crate::context::{is_pie_binary, get_reloc_model};
 use crate::common;
 use crate::LlvmCodegenBackend;
+use rustc::bug;
 use rustc::hir::def_id::LOCAL_CRATE;
 use rustc_codegen_ssa::back::write::{CodegenContext, ModuleConfig, run_assembler};
 use rustc_codegen_ssa::traits::*;
@@ -20,7 +21,8 @@
 use rustc::util::common::time_ext;
 use rustc_fs_util::{path_to_c_string, link_or_copy};
 use rustc_data_structures::small_c_str::SmallCStr;
-use errors::{Handler, FatalError};
+use rustc_errors::{Handler, FatalError};
+use log::debug;
 
 use std::ffi::CString;
 use std::fs;
@@ -55,7 +57,7 @@
     ("local-exec", llvm::ThreadLocalMode::LocalExec),
 ];
 
-pub fn llvm_err(handler: &errors::Handler, msg: &str) -> FatalError {
+pub fn llvm_err(handler: &rustc_errors::Handler, msg: &str) -> FatalError {
     match llvm::last_error() {
         Some(err) => handler.fatal(&format!("{}: {}", msg, err)),
         None => handler.fatal(&msg),
@@ -63,7 +65,7 @@
 }
 
 pub fn write_output_file(
-        handler: &errors::Handler,
+        handler: &rustc_errors::Handler,
         target: &'ll llvm::TargetMachine,
         pm: &llvm::PassManager<'ll>,
         m: &'ll llvm::Module,
diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs
index 6f72466..7509584 100644
--- a/src/librustc_codegen_llvm/builder.rs
+++ b/src/librustc_codegen_llvm/builder.rs
@@ -23,6 +23,8 @@
 use std::ops::{Deref, Range};
 use std::ptr;
 use std::iter::TrustedLen;
+use rustc_data_structures::const_cstr;
+use log::debug;
 
 // All Builders must have an llfn associated with them
 #[must_use]
diff --git a/src/librustc_codegen_llvm/callee.rs b/src/librustc_codegen_llvm/callee.rs
index e0db7ca..c0be87b 100644
--- a/src/librustc_codegen_llvm/callee.rs
+++ b/src/librustc_codegen_llvm/callee.rs
@@ -10,6 +10,7 @@
 use crate::context::CodegenCx;
 use crate::value::Value;
 use rustc_codegen_ssa::traits::*;
+use log::debug;
 
 use rustc::ty::{TypeFoldable, Instance};
 use rustc::ty::layout::{FnAbiExt, HasTyCtxt};
diff --git a/src/librustc_codegen_llvm/common.rs b/src/librustc_codegen_llvm/common.rs
index 419e99d..ff03c1f 100644
--- a/src/librustc_codegen_llvm/common.rs
+++ b/src/librustc_codegen_llvm/common.rs
@@ -8,6 +8,8 @@
 use crate::type_of::LayoutLlvmExt;
 use crate::value::Value;
 use rustc_codegen_ssa::traits::*;
+use rustc::bug;
+use log::debug;
 
 use crate::consts::const_alloc_to_llvm;
 use rustc::ty::layout::{HasDataLayout, LayoutOf, self, TyLayout, Size};
diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs
index 297aff9..11a105c 100644
--- a/src/librustc_codegen_llvm/consts.rs
+++ b/src/librustc_codegen_llvm/consts.rs
@@ -16,6 +16,8 @@
 use rustc_codegen_ssa::traits::*;
 use syntax::symbol::{Symbol, sym};
 use syntax_pos::Span;
+use rustc::{bug, span_bug};
+use log::debug;
 
 use rustc::ty::layout::{self, Size, Align, LayoutOf};
 
diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs
index 39ea1f6..2c894a5 100644
--- a/src/librustc_codegen_llvm/context.rs
+++ b/src/librustc_codegen_llvm/context.rs
@@ -12,6 +12,7 @@
 
 use rustc_data_structures::base_n;
 use rustc_data_structures::small_c_str::SmallCStr;
+use rustc::bug;
 use rustc::mir::mono::CodegenUnit;
 use rustc::session::config::{self, DebugInfo};
 use rustc::session::Session;
@@ -23,6 +24,7 @@
 use rustc_target::spec::{HasTargetSpec, Target};
 use rustc_codegen_ssa::base::wants_msvc_seh;
 use crate::callee::get_fn;
+use rustc_data_structures::const_cstr;
 
 use std::ffi::CStr;
 use std::cell::{Cell, RefCell};
diff --git a/src/librustc_codegen_llvm/debuginfo/gdb.rs b/src/librustc_codegen_llvm/debuginfo/gdb.rs
index 9ed1c17..739437a 100644
--- a/src/librustc_codegen_llvm/debuginfo/gdb.rs
+++ b/src/librustc_codegen_llvm/debuginfo/gdb.rs
@@ -7,6 +7,7 @@
 use crate::value::Value;
 use rustc::session::config::DebugInfo;
 use rustc_codegen_ssa::traits::*;
+use rustc::bug;
 
 use syntax::attr;
 use syntax::symbol::sym;
diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs
index 1847e4e..8327ff2 100644
--- a/src/librustc_codegen_llvm/debuginfo/metadata.rs
+++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs
@@ -35,10 +35,13 @@
 use rustc::util::nodemap::FxHashMap;
 use rustc_fs_util::path_to_c_string;
 use rustc_data_structures::small_c_str::SmallCStr;
+use rustc_data_structures::const_cstr;
 use rustc_target::abi::HasDataLayout;
 use syntax::ast;
 use syntax::symbol::{Interner, Symbol};
 use syntax_pos::{self, Span, FileName};
+use rustc::{bug, span_bug};
+use log::debug;
 
 use libc::{c_uint, c_longlong};
 use std::collections::hash_map::Entry;
diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs
index a3782ec..1de298d 100644
--- a/src/librustc_codegen_llvm/debuginfo/mod.rs
+++ b/src/librustc_codegen_llvm/debuginfo/mod.rs
@@ -33,6 +33,7 @@
 use libc::c_uint;
 use std::cell::RefCell;
 use std::ffi::CString;
+use log::debug;
 
 use smallvec::SmallVec;
 use syntax_pos::{self, BytePos, Span, Pos};
diff --git a/src/librustc_codegen_llvm/debuginfo/source_loc.rs b/src/librustc_codegen_llvm/debuginfo/source_loc.rs
index ccb3bde..82183fa 100644
--- a/src/librustc_codegen_llvm/debuginfo/source_loc.rs
+++ b/src/librustc_codegen_llvm/debuginfo/source_loc.rs
@@ -8,6 +8,7 @@
 use crate::llvm::debuginfo::DIScope;
 use crate::builder::Builder;
 use rustc_codegen_ssa::traits::*;
+use log::debug;
 
 use libc::c_uint;
 use syntax_pos::{Span, Pos};
diff --git a/src/librustc_codegen_llvm/declare.rs b/src/librustc_codegen_llvm/declare.rs
index fa9fc46..5144b92 100644
--- a/src/librustc_codegen_llvm/declare.rs
+++ b/src/librustc_codegen_llvm/declare.rs
@@ -22,6 +22,7 @@
 use rustc::session::config::Sanitizer;
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_codegen_ssa::traits::*;
+use log::debug;
 
 /// Declare a function.
 ///
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index 1767ad1..900f2d2 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -19,6 +19,7 @@
 use rustc::hir;
 use rustc_target::abi::HasDataLayout;
 use syntax::ast;
+use rustc::{bug, span_bug};
 
 use rustc_codegen_ssa::common::span_invalid_monomorphization_error;
 use rustc_codegen_ssa::traits::*;
diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs
index 00a84f8..1e1d74c 100644
--- a/src/librustc_codegen_llvm/lib.rs
+++ b/src/librustc_codegen_llvm/lib.rs
@@ -24,33 +24,11 @@
 use back::write::{create_target_machine, create_informational_target_machine};
 use syntax_pos::symbol::Symbol;
 
-extern crate rustc_demangle;
-extern crate flate2;
-#[macro_use] extern crate bitflags;
-extern crate libc;
-#[macro_use] extern crate rustc;
-extern crate rustc_target;
-#[macro_use] extern crate rustc_data_structures;
-extern crate rustc_feature;
-extern crate rustc_index;
-extern crate rustc_incremental;
-extern crate rustc_codegen_utils;
-extern crate rustc_codegen_ssa;
-extern crate rustc_fs_util;
-extern crate rustc_driver as _;
-
-#[macro_use] extern crate log;
-extern crate smallvec;
-extern crate syntax;
-extern crate syntax_pos;
-extern crate rustc_errors as errors;
-extern crate rustc_session;
-
 use rustc_codegen_ssa::traits::*;
 use rustc_codegen_ssa::back::write::{CodegenContext, ModuleConfig, FatLTOInput};
 use rustc_codegen_ssa::back::lto::{SerializedModule, LtoModuleCodegen, ThinModule};
 use rustc_codegen_ssa::CompiledModule;
-use errors::{FatalError, Handler};
+use rustc_errors::{FatalError, Handler};
 use rustc::dep_graph::WorkProduct;
 use syntax::expand::allocator::AllocatorKind;
 pub use llvm_util::target_features;
@@ -339,12 +317,6 @@
     }
 }
 
-/// This is the entrypoint for a hot plugged rustc_codegen_llvm
-#[no_mangle]
-pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
-    LlvmCodegenBackend::new()
-}
-
 pub struct ModuleLlvm {
     llcx: &'static mut llvm::Context,
     llmod_raw: *const llvm::Module,
diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs
index 5da3275..b8a1003 100644
--- a/src/librustc_codegen_llvm/llvm/ffi.rs
+++ b/src/librustc_codegen_llvm/llvm/ffi.rs
@@ -544,6 +544,7 @@
 
 pub mod debuginfo {
     use super::{InvariantOpaque, Metadata};
+    use bitflags::bitflags;
 
     #[repr(C)]
     pub struct DIBuilder<'a>(InvariantOpaque<'a>);
diff --git a/src/librustc_codegen_llvm/llvm/mod.rs b/src/librustc_codegen_llvm/llvm/mod.rs
index d2d4187..9757567 100644
--- a/src/librustc_codegen_llvm/llvm/mod.rs
+++ b/src/librustc_codegen_llvm/llvm/mod.rs
@@ -10,11 +10,11 @@
 
 use std::str::FromStr;
 use std::string::FromUtf8Error;
-use std::slice;
 use std::ffi::CStr;
 use std::cell::RefCell;
-use libc::{c_uint, c_char, size_t};
+use libc::c_uint;
 use rustc_data_structures::small_c_str::SmallCStr;
+use rustc_llvm::RustString;
 
 pub mod archive_ro;
 pub mod diagnostic;
@@ -81,21 +81,6 @@
     }
 }
 
-#[repr(C)]
-pub struct RustString {
-    bytes: RefCell<Vec<u8>>,
-}
-
-/// Appending to a Rust string -- used by RawRustStringOstream.
-#[no_mangle]
-pub unsafe extern "C" fn LLVMRustStringWriteImpl(sr: &RustString,
-                                                 ptr: *const c_char,
-                                                 size: size_t) {
-    let slice = slice::from_raw_parts(ptr as *const u8, size as usize);
-
-    sr.bytes.borrow_mut().extend_from_slice(slice);
-}
-
 pub fn SetInstructionCallConv(instr: &'a Value, cc: CallConv) {
     unsafe {
         LLVMSetInstructionCallConv(instr, cc as c_uint);
diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs
index 72612c4..4073938 100644
--- a/src/librustc_codegen_llvm/llvm_util.rs
+++ b/src/librustc_codegen_llvm/llvm_util.rs
@@ -8,6 +8,7 @@
 use std::ffi::CString;
 use rustc_feature::UnstableFeatures;
 use syntax::symbol::sym;
+use rustc::bug;
 
 use std::str;
 use std::slice;
diff --git a/src/librustc_codegen_llvm/metadata.rs b/src/librustc_codegen_llvm/metadata.rs
index cd72558..bbe42e3 100644
--- a/src/librustc_codegen_llvm/metadata.rs
+++ b/src/librustc_codegen_llvm/metadata.rs
@@ -6,6 +6,8 @@
 
 use rustc_data_structures::owning_ref::OwningRef;
 use rustc_codegen_ssa::METADATA_FILENAME;
+use log::debug;
+use rustc_data_structures::rustc_erase_owner;
 
 use std::path::Path;
 use std::slice;
diff --git a/src/librustc_codegen_llvm/mono_item.rs b/src/librustc_codegen_llvm/mono_item.rs
index cbc8af4..9f6bdd2 100644
--- a/src/librustc_codegen_llvm/mono_item.rs
+++ b/src/librustc_codegen_llvm/mono_item.rs
@@ -9,6 +9,7 @@
 use rustc::ty::{TypeFoldable, Instance};
 use rustc::ty::layout::{FnAbiExt, LayoutOf};
 use rustc_codegen_ssa::traits::*;
+use log::debug;
 
 pub use rustc::mir::mono::MonoItem;
 
diff --git a/src/librustc_codegen_llvm/type_.rs b/src/librustc_codegen_llvm/type_.rs
index f936367..e6677f3 100644
--- a/src/librustc_codegen_llvm/type_.rs
+++ b/src/librustc_codegen_llvm/type_.rs
@@ -5,6 +5,7 @@
 use crate::context::CodegenCx;
 use crate::value::Value;
 use rustc_codegen_ssa::traits::*;
+use rustc::bug;
 
 use crate::common;
 use crate::type_of::LayoutLlvmExt;
diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs
index d77bbb2..f9cbf4b 100644
--- a/src/librustc_codegen_llvm/type_of.rs
+++ b/src/librustc_codegen_llvm/type_of.rs
@@ -6,6 +6,8 @@
 use rustc_target::abi::TyLayoutMethods;
 use rustc::ty::print::obsolete::DefPathBasedNames;
 use rustc_codegen_ssa::traits::*;
+use log::debug;
+use rustc::bug;
 
 use std::fmt::Write;
 
diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml
index d1cb4cb..043cfc5 100644
--- a/src/librustc_driver/Cargo.toml
+++ b/src/librustc_driver/Cargo.toml
@@ -32,3 +32,6 @@
 rustc_resolve = { path = "../librustc_resolve" }
 syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
+
+[features]
+llvm = ['rustc_interface/llvm']
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 0594550..3230e04 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -42,7 +42,7 @@
 use rustc_codegen_utils::codegen_backend::CodegenBackend;
 use errors::{PResult, registry::Registry};
 use rustc_interface::{interface, Queries};
-use rustc_interface::util::get_codegen_sysroot;
+use rustc_interface::util::get_builtin_codegen_backend;
 use rustc_data_structures::sync::SeqCst;
 use rustc_feature::{find_gated_cfg, UnstableFeatures};
 use rustc_serialize::json::ToJson;
@@ -765,7 +765,7 @@
         println!("commit-date: {}", unw(commit_date_str()));
         println!("host: {}", config::host_triple());
         println!("release: {}", unw(release_str()));
-        get_codegen_sysroot("llvm")().print_version();
+        get_builtin_codegen_backend("llvm")().print_version();
     }
 }
 
@@ -1059,7 +1059,7 @@
     }
 
     if cg_flags.iter().any(|x| *x == "passes=list") {
-        get_codegen_sysroot("llvm")().print_passes();
+        get_builtin_codegen_backend("llvm")().print_passes();
         return None;
     }
 
diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml
index 7ab5ec2..58fd928 100644
--- a/src/librustc_interface/Cargo.toml
+++ b/src/librustc_interface/Cargo.toml
@@ -25,6 +25,7 @@
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_codegen_ssa = { path = "../librustc_codegen_ssa" }
 rustc_codegen_utils = { path = "../librustc_codegen_utils" }
+rustc_codegen_llvm = { path = "../librustc_codegen_llvm", optional = true }
 rustc_metadata = { path = "../librustc_metadata" }
 rustc_mir = { path = "../librustc_mir" }
 rustc_passes = { path = "../librustc_passes" }
@@ -39,3 +40,6 @@
 
 [dev-dependencies]
 rustc_target = { path = "../librustc_target" }
+
+[features]
+llvm = ['rustc_codegen_llvm']
diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs
index 8c225b8..c78b3ee 100644
--- a/src/librustc_interface/util.rs
+++ b/src/librustc_interface/util.rs
@@ -16,11 +16,9 @@
 use rustc_metadata::dynamic_lib::DynamicLibrary;
 use rustc_resolve::{self, Resolver};
 use std::env;
-use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
 use std::io::{self, Write};
 use std::mem;
 use std::path::{Path, PathBuf};
-use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::{Arc, Mutex, Once};
 use std::ops::DerefMut;
 use smallvec::SmallVec;
@@ -249,7 +247,7 @@
             filename if filename.contains(".") => {
                 load_backend_from_dylib(filename.as_ref())
             }
-            codegen_name => get_codegen_sysroot(codegen_name),
+            codegen_name => get_builtin_codegen_backend(codegen_name),
         };
 
         unsafe {
@@ -384,83 +382,16 @@
     }
 }
 
-pub fn get_codegen_sysroot(backend_name: &str) -> fn() -> Box<dyn CodegenBackend> {
-    // For now we only allow this function to be called once as it'll dlopen a
-    // few things, which seems to work best if we only do that once. In
-    // general this assertion never trips due to the once guard in `get_codegen_backend`,
-    // but there's a few manual calls to this function in this file we protect
-    // against.
-    static LOADED: AtomicBool = AtomicBool::new(false);
-    assert!(!LOADED.fetch_or(true, Ordering::SeqCst),
-            "cannot load the default codegen backend twice");
-
-    let target = session::config::host_triple();
-    let sysroot_candidates = sysroot_candidates();
-
-    let sysroot = sysroot_candidates.iter()
-        .map(|sysroot| {
-            let libdir = filesearch::relative_target_lib_path(&sysroot, &target);
-            sysroot.join(libdir).with_file_name(
-                option_env!("CFG_CODEGEN_BACKENDS_DIR").unwrap_or("codegen-backends"))
-        })
-        .filter(|f| {
-            info!("codegen backend candidate: {}", f.display());
-            f.exists()
-        })
-        .next();
-    let sysroot = sysroot.unwrap_or_else(|| {
-        let candidates = sysroot_candidates.iter()
-            .map(|p| p.display().to_string())
-            .collect::<Vec<_>>()
-            .join("\n* ");
-        let err = format!("failed to find a `codegen-backends` folder \
-                           in the sysroot candidates:\n* {}", candidates);
-        early_error(ErrorOutputType::default(), &err);
-    });
-    info!("probing {} for a codegen backend", sysroot.display());
-
-    let d = sysroot.read_dir().unwrap_or_else(|e| {
-        let err = format!("failed to load default codegen backend, couldn't \
-                           read `{}`: {}", sysroot.display(), e);
-        early_error(ErrorOutputType::default(), &err);
-    });
-
-    let mut file: Option<PathBuf> = None;
-
-    let expected_name = format!("rustc_codegen_llvm-{}", backend_name);
-    for entry in d.filter_map(|e| e.ok()) {
-        let path = entry.path();
-        let filename = match path.file_name().and_then(|s| s.to_str()) {
-            Some(s) => s,
-            None => continue,
-        };
-        if !(filename.starts_with(DLL_PREFIX) && filename.ends_with(DLL_SUFFIX)) {
-            continue
-        }
-        let name = &filename[DLL_PREFIX.len() .. filename.len() - DLL_SUFFIX.len()];
-        if name != expected_name {
-            continue
-        }
-        if let Some(ref prev) = file {
-            let err = format!("duplicate codegen backends found\n\
-                               first:  {}\n\
-                               second: {}\n\
-            ", prev.display(), path.display());
-            early_error(ErrorOutputType::default(), &err);
-        }
-        file = Some(path.clone());
-    }
-
-    match file {
-        Some(ref s) => return load_backend_from_dylib(s),
-        None => {
-            let err = format!("failed to load default codegen backend for `{}`, \
-                               no appropriate codegen dylib found in `{}`",
-                              backend_name, sysroot.display());
-            early_error(ErrorOutputType::default(), &err);
+pub fn get_builtin_codegen_backend(backend_name: &str) -> fn() -> Box<dyn CodegenBackend> {
+    #[cfg(feature = "llvm")]
+    {
+        if backend_name == "llvm" {
+            return rustc_codegen_llvm::LlvmCodegenBackend::new;
         }
     }
 
+    let err = format!("unsupported builtin codegen backend `{}`", backend_name);
+    early_error(ErrorOutputType::default(), &err);
 }
 
 pub(crate) fn compute_crate_disambiguator(session: &Session) -> CrateDisambiguator {
diff --git a/src/librustc_llvm/Cargo.toml b/src/librustc_llvm/Cargo.toml
index 0fe327d..4fc02e3 100644
--- a/src/librustc_llvm/Cargo.toml
+++ b/src/librustc_llvm/Cargo.toml
@@ -13,6 +13,9 @@
 static-libstdcpp = []
 emscripten = []
 
+[dependencies]
+libc = "0.2"
+
 [build-dependencies]
 build_helper = { path = "../build_helper" }
 cc = "1.0.1"
diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs
index 647d473..9c8943a 100644
--- a/src/librustc_llvm/lib.rs
+++ b/src/librustc_llvm/lib.rs
@@ -5,6 +5,26 @@
 
 // NOTE: This crate only exists to allow linking on mingw targets.
 
+use std::cell::RefCell;
+use std::slice;
+use libc::{c_char, size_t};
+
+
+#[repr(C)]
+pub struct RustString {
+    pub bytes: RefCell<Vec<u8>>,
+}
+
+/// Appending to a Rust string -- used by RawRustStringOstream.
+#[no_mangle]
+pub unsafe extern "C" fn LLVMRustStringWriteImpl(sr: &RustString,
+                                                 ptr: *const c_char,
+                                                 size: size_t) {
+    let slice = slice::from_raw_parts(ptr as *const u8, size as usize);
+
+    sr.bytes.borrow_mut().extend_from_slice(slice);
+}
+
 /// Initialize targets enabled by the build script via `cfg(llvm_component = "...")`.
 /// N.B., this function can't be moved to `rustc_codegen_llvm` because of the `cfg`s.
 pub fn initialize_available_targets() {
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs
index 37a9381..c372032 100644
--- a/src/librustc_mir/hair/pattern/_match.rs
+++ b/src/librustc_mir/hair/pattern/_match.rs
@@ -238,7 +238,7 @@
 use rustc::hir::def_id::DefId;
 use rustc::hir::{HirId, RangeEnd};
 use rustc::ty::layout::{Integer, IntegerExt, Size, VariantIdx};
-use rustc::ty::{self, Const, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::{self, Const, Ty, TyCtxt, TypeFoldable, VariantDef};
 
 use rustc::lint;
 use rustc::mir::interpret::{truncate, AllocId, ConstValue, Pointer, Scalar};
@@ -354,7 +354,7 @@
 }
 
 impl<'tcx> Pat<'tcx> {
-    fn is_wildcard(&self) -> bool {
+    pub(super) fn is_wildcard(&self) -> bool {
         match *self.kind {
             PatKind::Binding { subpattern: None, .. } | PatKind::Wild => true,
             _ => false,
@@ -596,9 +596,21 @@
         }
     }
 
-    fn is_local(&self, ty: Ty<'tcx>) -> bool {
+    // Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`.
+    pub fn is_foreign_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool {
         match ty.kind {
-            ty::Adt(adt_def, ..) => adt_def.did.is_local(),
+            ty::Adt(def, ..) => {
+                def.is_enum() && def.is_variant_list_non_exhaustive() && !def.did.is_local()
+            }
+            _ => false,
+        }
+    }
+
+    // Returns whether the given variant is from another crate and has its fields declared
+    // `#[non_exhaustive]`.
+    fn is_foreign_non_exhaustive_variant(&self, ty: Ty<'tcx>, variant: &VariantDef) -> bool {
+        match ty.kind {
+            ty::Adt(def, ..) => variant.is_field_list_non_exhaustive() && !def.did.is_local(),
             _ => false,
         }
     }
@@ -758,6 +770,10 @@
     // Returns the set of constructors covered by `self` but not by
     // anything in `other_ctors`.
     fn subtract_ctors(&self, other_ctors: &Vec<Constructor<'tcx>>) -> Vec<Constructor<'tcx>> {
+        if other_ctors.is_empty() {
+            return vec![self.clone()];
+        }
+
         match self {
             // Those constructors can only match themselves.
             Single | Variant(_) | ConstantValue(..) | FloatRange(..) => {
@@ -858,8 +874,7 @@
                         vec![Pat::wildcard_from_ty(substs.type_at(0))]
                     } else {
                         let variant = &adt.variants[self.variant_index_for_adt(cx, adt)];
-                        let is_non_exhaustive =
-                            variant.is_field_list_non_exhaustive() && !cx.is_local(ty);
+                        let is_non_exhaustive = cx.is_foreign_non_exhaustive_variant(ty, variant);
                         variant
                             .fields
                             .iter()
@@ -1205,6 +1220,8 @@
 ///
 /// We make sure to omit constructors that are statically impossible. E.g., for
 /// `Option<!>`, we do not include `Some(_)` in the returned list of constructors.
+/// Invariant: this returns an empty `Vec` if and only if the type is uninhabited (as determined by
+/// `cx.is_uninhabited()`).
 fn all_constructors<'a, 'tcx>(
     cx: &mut MatchCheckCtxt<'a, 'tcx>,
     pcx: PatCtxt<'tcx>,
@@ -1235,47 +1252,45 @@
             vec![Slice(Slice { array_len: None, kind })]
         }
         ty::Adt(def, substs) if def.is_enum() => {
-            let ctors: Vec<_> = def
-                .variants
-                .iter()
-                .filter(|v| {
-                    !cx.tcx.features().exhaustive_patterns
-                        || !v
-                            .uninhabited_from(cx.tcx, substs, def.adt_kind())
+            let ctors: Vec<_> = if cx.tcx.features().exhaustive_patterns {
+                // If `exhaustive_patterns` is enabled, we exclude variants known to be
+                // uninhabited.
+                def.variants
+                    .iter()
+                    .filter(|v| {
+                        !v.uninhabited_from(cx.tcx, substs, def.adt_kind())
                             .contains(cx.tcx, cx.module)
-                })
-                .map(|v| Variant(v.def_id))
-                .collect();
-
-            // If our scrutinee is *privately* an empty enum, we must treat it as though it had an
-            // "unknown" constructor (in that case, all other patterns obviously can't be variants)
-            // to avoid exposing its emptyness. See the `match_privately_empty` test for details.
-            // FIXME: currently the only way I know of something can be a privately-empty enum is
-            // when the exhaustive_patterns feature flag is not present, so this is only needed for
-            // that case.
-            let is_privately_empty = ctors.is_empty() && !cx.is_uninhabited(pcx.ty);
-            // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an
-            // additionnal "unknown" constructor.
-            let is_declared_nonexhaustive =
-                def.is_variant_list_non_exhaustive() && !cx.is_local(pcx.ty);
-
-            if is_privately_empty || is_declared_nonexhaustive {
-                // There is no point in enumerating all possible variants, because the user can't
-                // actually match against them themselves. So we return only the fictitious
-                // constructor.
-                // E.g., in an example like:
-                // ```
-                //     let err: io::ErrorKind = ...;
-                //     match err {
-                //         io::ErrorKind::NotFound => {},
-                //     }
-                // ```
-                // we don't want to show every possible IO error, but instead have only `_` as the
-                // witness.
-                vec![NonExhaustive]
+                    })
+                    .map(|v| Variant(v.def_id))
+                    .collect()
             } else {
-                ctors
-            }
+                def.variants.iter().map(|v| Variant(v.def_id)).collect()
+            };
+
+            // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an
+            // additional "unknown" constructor.
+            // There is no point in enumerating all possible variants, because the user can't
+            // actually match against them all themselves. So we always return only the fictitious
+            // constructor.
+            // E.g., in an example like:
+            // ```
+            //     let err: io::ErrorKind = ...;
+            //     match err {
+            //         io::ErrorKind::NotFound => {},
+            //     }
+            // ```
+            // we don't want to show every possible IO error, but instead have only `_` as the
+            // witness.
+            let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(pcx.ty);
+
+            // If `exhaustive_patterns` is disabled and our scrutinee is an empty enum, we treat it
+            // as though it had an "unknown" constructor to avoid exposing its emptyness. Note that
+            // an empty match will still be considered exhaustive because that case is handled
+            // separately in `check_match`.
+            let is_secretly_empty =
+                def.variants.is_empty() && !cx.tcx.features().exhaustive_patterns;
+
+            if is_secretly_empty || is_declared_nonexhaustive { vec![NonExhaustive] } else { ctors }
         }
         ty::Char => {
             vec![
@@ -1605,6 +1620,7 @@
     v: &PatStack<'p, 'tcx>,
     witness_preference: WitnessPreference,
     hir_id: HirId,
+    is_top_level: bool,
 ) -> Usefulness<'tcx, 'p> {
     let &Matrix(ref rows) = matrix;
     debug!("is_useful({:#?}, {:#?})", matrix, v);
@@ -1632,7 +1648,7 @@
         let mut unreachable_pats = Vec::new();
         let mut any_is_useful = false;
         for v in vs {
-            let res = is_useful(cx, &matrix, &v, witness_preference, hir_id);
+            let res = is_useful(cx, &matrix, &v, witness_preference, hir_id, false);
             match res {
                 Useful(pats) => {
                     any_is_useful = true;
@@ -1732,7 +1748,7 @@
         } else {
             let matrix = matrix.specialize_wildcard();
             let v = v.to_tail();
-            let usefulness = is_useful(cx, &matrix, &v, witness_preference, hir_id);
+            let usefulness = is_useful(cx, &matrix, &v, witness_preference, hir_id, false);
 
             // In this case, there's at least one "free"
             // constructor that is only matched against by
@@ -1761,7 +1777,10 @@
             // `(<direction-1>, <direction-2>, true)` - we are
             // satisfied with `(_, _, true)`. In this case,
             // `used_ctors` is empty.
-            if missing_ctors.all_ctors_are_missing() {
+            // The exception is: if we are at the top-level, for example in an empty match, we
+            // sometimes prefer reporting the list of constructors instead of just `_`.
+            let report_ctors_rather_than_wildcard = is_top_level && !IntRange::is_integral(pcx.ty);
+            if missing_ctors.all_ctors_are_missing() && !report_ctors_rather_than_wildcard {
                 // All constructors are unused. Add a wild pattern
                 // rather than each individual constructor.
                 usefulness.apply_wildcard(pcx.ty)
@@ -1793,7 +1812,7 @@
         cx.pattern_arena.alloc_from_iter(ctor.wildcard_subpatterns(cx, lty));
     let matrix = matrix.specialize_constructor(cx, &ctor, ctor_wild_subpatterns);
     v.specialize_constructor(cx, &ctor, ctor_wild_subpatterns)
-        .map(|v| is_useful(cx, &matrix, &v, witness_preference, hir_id))
+        .map(|v| is_useful(cx, &matrix, &v, witness_preference, hir_id, false))
         .map(|u| u.apply_constructor(cx, &ctor, lty))
         .unwrap_or(NotUseful)
 }
@@ -2308,7 +2327,7 @@
 
         PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => {
             let ref variant = adt_def.variants[variant_index];
-            let is_non_exhaustive = variant.is_field_list_non_exhaustive() && !cx.is_local(pat.ty);
+            let is_non_exhaustive = cx.is_foreign_non_exhaustive_variant(pat.ty, variant);
             Some(Variant(variant.def_id))
                 .filter(|variant_constructor| variant_constructor == constructor)
                 .map(|_| {
diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs
index 737af3e..8156cfe 100644
--- a/src/librustc_mir/hair/pattern/check_match.rs
+++ b/src/librustc_mir/hair/pattern/check_match.rs
@@ -148,8 +148,8 @@
                         self.tables,
                     );
                     patcx.include_lint_checks();
-                    let pattern: &_ =
-                        cx.pattern_arena.alloc(expand_pattern(cx, patcx.lower_pattern(&arm.pat)));
+                    let pattern = patcx.lower_pattern(&arm.pat);
+                    let pattern: &_ = cx.pattern_arena.alloc(expand_pattern(cx, pattern));
                     if !patcx.errors.is_empty() {
                         patcx.report_inlining_errors(arm.pat.span);
                         have_errors = true;
@@ -166,73 +166,12 @@
             // Fourth, check for unreachable arms.
             let matrix = check_arms(cx, &inlined_arms, source);
 
-            // Then, if the match has no arms, check whether the scrutinee
-            // is uninhabited.
-            let pat_ty = self.tables.node_type(scrut.hir_id);
-            let module = self.tcx.hir().get_module_parent(scrut.hir_id);
-            let mut def_span = None;
-            let mut missing_variants = vec![];
-            if inlined_arms.is_empty() {
-                let scrutinee_is_uninhabited = if self.tcx.features().exhaustive_patterns {
-                    self.tcx.is_ty_uninhabited_from(module, pat_ty)
-                } else {
-                    match pat_ty.kind {
-                        ty::Never => true,
-                        ty::Adt(def, _) => {
-                            def_span = self.tcx.hir().span_if_local(def.did);
-                            if def.variants.len() < 4 && !def.variants.is_empty() {
-                                // keep around to point at the definition of non-covered variants
-                                missing_variants =
-                                    def.variants.iter().map(|variant| variant.ident).collect();
-                            }
-
-                            let is_non_exhaustive_and_non_local =
-                                def.is_variant_list_non_exhaustive() && !def.did.is_local();
-
-                            !(is_non_exhaustive_and_non_local) && def.variants.is_empty()
-                        }
-                        _ => false,
-                    }
-                };
-                if !scrutinee_is_uninhabited {
-                    // We know the type is inhabited, so this must be wrong
-                    let mut err = create_e0004(
-                        self.tcx.sess,
-                        scrut.span,
-                        format!(
-                            "non-exhaustive patterns: {}",
-                            match missing_variants.len() {
-                                0 => format!("type `{}` is non-empty", pat_ty),
-                                1 => format!(
-                                    "pattern `{}` of type `{}` is not handled",
-                                    missing_variants[0].name, pat_ty,
-                                ),
-                                _ => format!(
-                                    "multiple patterns of type `{}` are not handled",
-                                    pat_ty
-                                ),
-                            }
-                        ),
-                    );
-                    err.help(
-                        "ensure that all possible cases are being handled, \
-                         possibly by adding wildcards or more match arms",
-                    );
-                    if let Some(sp) = def_span {
-                        err.span_label(sp, format!("`{}` defined here", pat_ty));
-                    }
-                    // point at the definition of non-covered enum variants
-                    for variant in &missing_variants {
-                        err.span_label(variant.span, "variant not covered");
-                    }
-                    err.emit();
-                }
-                // If the type *is* uninhabited, it's vacuously exhaustive
-                return;
-            }
-
+            // Fifth, check if the match is exhaustive.
             let scrut_ty = self.tables.node_type(scrut.hir_id);
-            check_exhaustive(cx, scrut_ty, scrut.span, &matrix, scrut.hir_id);
+            // Note: An empty match isn't the same as an empty matrix for diagnostics purposes,
+            // since an empty matrix can occur when there are arms, if those arms all have guards.
+            let is_empty_match = inlined_arms.is_empty();
+            check_exhaustive(cx, scrut_ty, scrut.span, &matrix, scrut.hir_id, is_empty_match);
         })
     }
 
@@ -390,7 +329,7 @@
     for (arm_index, (pat, hir_pat, has_guard)) in arms.iter().enumerate() {
         let v = PatStack::from_pattern(pat);
 
-        match is_useful(cx, &seen, &v, LeaveOutWitness, hir_pat.hir_id) {
+        match is_useful(cx, &seen, &v, LeaveOutWitness, hir_pat.hir_id, true) {
             NotUseful => {
                 match source {
                     hir::MatchSource::IfDesugar { .. } | hir::MatchSource::WhileDesugar => bug!(),
@@ -478,7 +417,8 @@
     hir_id: HirId,
 ) -> Result<(), Vec<super::Pat<'tcx>>> {
     let wild_pattern = cx.pattern_arena.alloc(super::Pat::wildcard_from_ty(ty));
-    match is_useful(cx, matrix, &PatStack::from_pattern(wild_pattern), ConstructWitness, hir_id) {
+    let v = PatStack::from_pattern(wild_pattern);
+    match is_useful(cx, matrix, &v, ConstructWitness, hir_id, true) {
         NotUseful => Ok(()), // This is good, wildcard pattern isn't reachable.
         UsefulWithWitness(pats) => Err(if pats.is_empty() {
             bug!("Exhaustiveness check returned no witnesses")
@@ -495,25 +435,60 @@
     sp: Span,
     matrix: &Matrix<'p, 'tcx>,
     hir_id: HirId,
+    is_empty_match: bool,
 ) {
+    // In the absence of the `exhaustive_patterns` feature, empty matches are not detected by
+    // `is_useful` to exhaustively match uninhabited types, so we manually check here.
+    if is_empty_match && !cx.tcx.features().exhaustive_patterns {
+        let scrutinee_is_visibly_uninhabited = match scrut_ty.kind {
+            ty::Never => true,
+            ty::Adt(def, _) => {
+                def.is_enum()
+                    && def.variants.is_empty()
+                    && !cx.is_foreign_non_exhaustive_enum(scrut_ty)
+            }
+            _ => false,
+        };
+        if scrutinee_is_visibly_uninhabited {
+            // If the type *is* uninhabited, an empty match is vacuously exhaustive.
+            return;
+        }
+    }
+
     let witnesses = match check_not_useful(cx, scrut_ty, matrix, hir_id) {
         Ok(_) => return,
         Err(err) => err,
     };
 
-    let joined_patterns = joined_uncovered_patterns(&witnesses);
-    let mut err = create_e0004(
-        cx.tcx.sess,
-        sp,
-        format!("non-exhaustive patterns: {} not covered", joined_patterns),
-    );
-    err.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns));
+    let non_empty_enum = match scrut_ty.kind {
+        ty::Adt(def, _) => def.is_enum() && !def.variants.is_empty(),
+        _ => false,
+    };
+    // In the case of an empty match, replace the '`_` not covered' diagnostic with something more
+    // informative.
+    let mut err;
+    if is_empty_match && !non_empty_enum {
+        err = create_e0004(
+            cx.tcx.sess,
+            sp,
+            format!("non-exhaustive patterns: type `{}` is non-empty", scrut_ty),
+        );
+    } else {
+        let joined_patterns = joined_uncovered_patterns(&witnesses);
+        err = create_e0004(
+            cx.tcx.sess,
+            sp,
+            format!("non-exhaustive patterns: {} not covered", joined_patterns),
+        );
+        err.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns));
+    };
+
     adt_defined_here(cx, &mut err, scrut_ty, &witnesses);
     err.help(
         "ensure that all possible cases are being handled, \
          possibly by adding wildcards or more match arms",
-    )
-    .emit();
+    );
+    err.emit();
 }
 
 fn joined_uncovered_patterns(witnesses: &[super::Pat<'_>]) -> String {
diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs
index efa0d26..916ea3dc 100644
--- a/src/librustc_mir/interpret/traits.rs
+++ b/src/librustc_mir/interpret/traits.rs
@@ -140,7 +140,18 @@
         let fn_sig = drop_instance.ty(*self.tcx).fn_sig(*self.tcx);
         let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, &fn_sig);
         // The drop function takes `*mut T` where `T` is the type being dropped, so get that.
-        let ty = fn_sig.inputs()[0].builtin_deref(true).unwrap().ty;
+        let args = fn_sig.inputs();
+        if args.len() != 1 {
+            throw_ub_format!(
+                "drop fn should have 1 argument, but signature is {:?}", fn_sig
+            );
+        }
+        let ty = args[0].builtin_deref(true)
+            .ok_or_else(|| err_ub_format!(
+                "drop fn argument type {} is not a pointer type",
+                args[0]
+            ))?
+            .ty;
         Ok((drop_instance, ty))
     }
 
diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs
index e358df2..1dbcfe5 100644
--- a/src/librustc_mir/interpret/validity.rs
+++ b/src/librustc_mir/interpret/validity.rs
@@ -22,28 +22,23 @@
 
 macro_rules! throw_validation_failure {
     ($what:expr, $where:expr, $details:expr) => {{
-        let where_ = path_format(&$where);
-        let where_ = if where_.is_empty() {
-            String::new()
-        } else {
-            format!(" at {}", where_)
-        };
-        throw_unsup!(ValidationFailure(format!(
-            "encountered {}{}, but expected {}",
-            $what, where_, $details,
-        )))
+        let mut msg = format!("encountered {}", $what);
+        let where_ = &$where;
+        if !where_.is_empty() {
+            msg.push_str(" at ");
+            write_path(&mut msg, where_);
+        }
+        write!(&mut msg, ", but expected {}", $details).unwrap();
+        throw_unsup!(ValidationFailure(msg))
     }};
     ($what:expr, $where:expr) => {{
-        let where_ = path_format(&$where);
-        let where_ = if where_.is_empty() {
-            String::new()
-        } else {
-            format!(" at {}", where_)
-        };
-        throw_unsup!(ValidationFailure(format!(
-            "encountered {}{}",
-            $what, where_,
-        )))
+        let mut msg = format!("encountered {}", $what);
+        let where_ = &$where;
+        if !where_.is_empty() {
+            msg.push_str(" at ");
+            write_path(&mut msg, where_);
+        }
+        throw_unsup!(ValidationFailure(msg))
     }};
 }
 
@@ -60,7 +55,7 @@
             Ok(x) => x,
             Err(_) => throw_validation_failure!($what, $where),
         }
-    }}
+    }};
 }
 
 /// We want to show a nice path to the invalid field for diagnostics,
@@ -113,10 +108,9 @@
 }
 
 /// Format a path
-fn path_format(path: &Vec<PathElem>) -> String {
+fn write_path(out: &mut String, path: &Vec<PathElem>) {
     use self::PathElem::*;
 
-    let mut out = String::new();
     for elem in path.iter() {
         match elem {
             Field(name) => write!(out, ".{}", name),
@@ -135,7 +129,6 @@
             DynDowncast => write!(out, ".<dyn-downcast>"),
         }.unwrap()
     }
-    out
 }
 
 // Test if a range that wraps at overflow contains `test`
@@ -428,7 +421,7 @@
                             err_unsup!(InvalidNullPointerUsage) =>
                                 throw_validation_failure!("NULL reference", self.path),
                             err_unsup!(AlignmentCheckFailed { required, has }) =>
-                                throw_validation_failure!(format!("unaligned reference \
+                                throw_validation_failure!(format_args!("unaligned reference \
                                     (required {} byte alignment but found {})",
                                     required.bytes(), has.bytes()), self.path),
                             err_unsup!(ReadBytesAsPointer) =>
@@ -519,7 +512,7 @@
         let value = try_validation!(value.not_undef(),
             value,
             self.path,
-            format!(
+            format_args!(
                 "something {}",
                 wrapping_range_format(&layout.valid_range, max_hi),
             )
@@ -532,7 +525,7 @@
                         throw_validation_failure!(
                             "a potentially NULL pointer",
                             self.path,
-                            format!(
+                            format_args!(
                                 "something that cannot possibly fail to be {}",
                                 wrapping_range_format(&layout.valid_range, max_hi)
                             )
@@ -545,7 +538,7 @@
                     throw_validation_failure!(
                         "a pointer",
                         self.path,
-                        format!(
+                        format_args!(
                             "something that cannot possibly fail to be {}",
                             wrapping_range_format(&layout.valid_range, max_hi)
                         )
@@ -562,7 +555,7 @@
             throw_validation_failure!(
                 bits,
                 self.path,
-                format!("something {}", wrapping_range_format(&layout.valid_range, max_hi))
+                format_args!("something {}", wrapping_range_format(&layout.valid_range, max_hi))
             )
         }
     }
diff --git a/src/rustc/Cargo.toml b/src/rustc/Cargo.toml
index 997d139..86a93d7 100644
--- a/src/rustc/Cargo.toml
+++ b/src/rustc/Cargo.toml
@@ -23,3 +23,4 @@
 
 [features]
 jemalloc = ['jemalloc-sys']
+llvm = ['rustc_driver/llvm']
diff --git a/src/test/ui/error-codes/E0004-2.stderr b/src/test/ui/error-codes/E0004-2.stderr
index db0a2b5..f5b41cd 100644
--- a/src/test/ui/error-codes/E0004-2.stderr
+++ b/src/test/ui/error-codes/E0004-2.stderr
@@ -1,8 +1,8 @@
-error[E0004]: non-exhaustive patterns: multiple patterns of type `std::option::Option<i32>` are not handled
+error[E0004]: non-exhaustive patterns: `None` and `Some(_)` not covered
   --> $DIR/E0004-2.rs:4:11
    |
 LL |     match x { }
-   |           ^
+   |           ^ patterns `None` and `Some(_)` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
diff --git a/src/test/ui/issues/issue-3601.stderr b/src/test/ui/issues/issue-3601.stderr
index fa0fa334..445eb41 100644
--- a/src/test/ui/issues/issue-3601.stderr
+++ b/src/test/ui/issues/issue-3601.stderr
@@ -1,8 +1,8 @@
-error[E0004]: non-exhaustive patterns: `_` not covered
+error[E0004]: non-exhaustive patterns: `Box(_)` not covered
   --> $DIR/issue-3601.rs:30:44
    |
 LL |         box NodeKind::Element(ed) => match ed.kind {
-   |                                            ^^^^^^^ pattern `_` not covered
+   |                                            ^^^^^^^ pattern `Box(_)` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
diff --git a/src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr b/src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr
index 792ab6f..1b1096c 100644
--- a/src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr
+++ b/src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr
@@ -9,8 +9,13 @@
 error[E0004]: non-exhaustive patterns: type `Foo` is non-empty
   --> $DIR/always-inhabited-union-ref.rs:27:11
    |
-LL |     match uninhab_union() {
-   |           ^^^^^^^^^^^^^^^
+LL | / pub union Foo {
+LL | |     foo: !,
+LL | | }
+   | |_- `Foo` defined here
+...
+LL |       match uninhab_union() {
+   |             ^^^^^^^^^^^^^^^
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
diff --git a/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs b/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs
new file mode 100644
index 0000000..57b6b91
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs
@@ -0,0 +1,93 @@
+#![feature(never_type)]
+#![feature(exhaustive_patterns)]
+#![deny(unreachable_patterns)]
+enum Foo {}
+
+struct NonEmptyStruct(bool); //~ `NonEmptyStruct` defined here
+union NonEmptyUnion1 { //~ `NonEmptyUnion1` defined here
+    foo: (),
+}
+union NonEmptyUnion2 { //~ `NonEmptyUnion2` defined here
+    foo: (),
+    bar: (),
+}
+enum NonEmptyEnum1 { //~ `NonEmptyEnum1` defined here
+    Foo(bool),
+    //~^ not covered
+    //~| not covered
+}
+enum NonEmptyEnum2 { //~ `NonEmptyEnum2` defined here
+    Foo(bool),
+    //~^ not covered
+    //~| not covered
+    Bar,
+    //~^ not covered
+    //~| not covered
+}
+enum NonEmptyEnum5 { //~ `NonEmptyEnum5` defined here
+    V1, V2, V3, V4, V5,
+}
+
+macro_rules! match_empty {
+    ($e:expr) => {
+        match $e {}
+    };
+}
+macro_rules! match_false {
+    ($e:expr) => {
+        match $e {
+            _ if false => {}
+        }
+    };
+}
+
+fn foo(x: Foo) {
+    match_empty!(x); // ok
+    match x {
+        _ => {}, //~ ERROR unreachable pattern
+    }
+    match x {
+        _ if false => {}, //~ ERROR unreachable pattern
+    }
+}
+
+fn main() {
+    match None::<!> {
+        None => {}
+        Some(_) => {} //~ ERROR unreachable pattern
+    }
+    match None::<Foo> {
+        None => {}
+        Some(_) => {} //~ ERROR unreachable pattern
+    }
+
+    match_empty!(0u8);
+    //~^ ERROR type `u8` is non-empty
+    match_empty!(NonEmptyStruct(true));
+    //~^ ERROR type `NonEmptyStruct` is non-empty
+    match_empty!((NonEmptyUnion1 { foo: () }));
+    //~^ ERROR type `NonEmptyUnion1` is non-empty
+    match_empty!((NonEmptyUnion2 { foo: () }));
+    //~^ ERROR type `NonEmptyUnion2` is non-empty
+    match_empty!(NonEmptyEnum1::Foo(true));
+    //~^ ERROR `Foo(_)` not covered
+    match_empty!(NonEmptyEnum2::Foo(true));
+    //~^ ERROR `Foo(_)` and `Bar` not covered
+    match_empty!(NonEmptyEnum5::V1);
+    //~^ ERROR `V1`, `V2`, `V3` and 2 more not covered
+
+    match_false!(0u8);
+    //~^ ERROR `_` not covered
+    match_false!(NonEmptyStruct(true));
+    //~^ ERROR `NonEmptyStruct(_)` not covered
+    match_false!((NonEmptyUnion1 { foo: () }));
+    //~^ ERROR `NonEmptyUnion1 { .. }` not covered
+    match_false!((NonEmptyUnion2 { foo: () }));
+    //~^ ERROR `NonEmptyUnion2 { .. }` not covered
+    match_false!(NonEmptyEnum1::Foo(true));
+    //~^ ERROR `Foo(_)` not covered
+    match_false!(NonEmptyEnum2::Foo(true));
+    //~^ ERROR `Foo(_)` and `Bar` not covered
+    match_false!(NonEmptyEnum5::V1);
+    //~^ ERROR `V1`, `V2`, `V3` and 2 more not covered
+}
diff --git a/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.stderr b/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.stderr
new file mode 100644
index 0000000..f242ecf
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.stderr
@@ -0,0 +1,223 @@
+error: unreachable pattern
+  --> $DIR/match-empty-exhaustive_patterns.rs:47:9
+   |
+LL |         _ => {},
+   |         ^
+   |
+note: lint level defined here
+  --> $DIR/match-empty-exhaustive_patterns.rs:3:9
+   |
+LL | #![deny(unreachable_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/match-empty-exhaustive_patterns.rs:50:9
+   |
+LL |         _ if false => {},
+   |         ^
+
+error: unreachable pattern
+  --> $DIR/match-empty-exhaustive_patterns.rs:57:9
+   |
+LL |         Some(_) => {}
+   |         ^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/match-empty-exhaustive_patterns.rs:61:9
+   |
+LL |         Some(_) => {}
+   |         ^^^^^^^
+
+error[E0004]: non-exhaustive patterns: type `u8` is non-empty
+  --> $DIR/match-empty-exhaustive_patterns.rs:64:18
+   |
+LL |     match_empty!(0u8);
+   |                  ^^^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyStruct` is non-empty
+  --> $DIR/match-empty-exhaustive_patterns.rs:66:18
+   |
+LL | struct NonEmptyStruct(bool);
+   | ---------------------------- `NonEmptyStruct` defined here
+...
+LL |     match_empty!(NonEmptyStruct(true));
+   |                  ^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
+  --> $DIR/match-empty-exhaustive_patterns.rs:68:18
+   |
+LL | / union NonEmptyUnion1 {
+LL | |     foo: (),
+LL | | }
+   | |_- `NonEmptyUnion1` defined here
+...
+LL |       match_empty!((NonEmptyUnion1 { foo: () }));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
+  --> $DIR/match-empty-exhaustive_patterns.rs:70:18
+   |
+LL | / union NonEmptyUnion2 {
+LL | |     foo: (),
+LL | |     bar: (),
+LL | | }
+   | |_- `NonEmptyUnion2` defined here
+...
+LL |       match_empty!((NonEmptyUnion2 { foo: () }));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
+  --> $DIR/match-empty-exhaustive_patterns.rs:72:18
+   |
+LL | / enum NonEmptyEnum1 {
+LL | |     Foo(bool),
+   | |     --- not covered
+LL | |
+LL | |
+LL | | }
+   | |_- `NonEmptyEnum1` defined here
+...
+LL |       match_empty!(NonEmptyEnum1::Foo(true));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
+  --> $DIR/match-empty-exhaustive_patterns.rs:74:18
+   |
+LL | / enum NonEmptyEnum2 {
+LL | |     Foo(bool),
+   | |     --- not covered
+LL | |
+LL | |
+LL | |     Bar,
+   | |     --- not covered
+LL | |
+LL | |
+LL | | }
+   | |_- `NonEmptyEnum2` defined here
+...
+LL |       match_empty!(NonEmptyEnum2::Foo(true));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
+  --> $DIR/match-empty-exhaustive_patterns.rs:76:18
+   |
+LL | / enum NonEmptyEnum5 {
+LL | |     V1, V2, V3, V4, V5,
+LL | | }
+   | |_- `NonEmptyEnum5` defined here
+...
+LL |       match_empty!(NonEmptyEnum5::V1);
+   |                    ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+  --> $DIR/match-empty-exhaustive_patterns.rs:79:18
+   |
+LL |     match_false!(0u8);
+   |                  ^^^ pattern `_` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `NonEmptyStruct(_)` not covered
+  --> $DIR/match-empty-exhaustive_patterns.rs:81:18
+   |
+LL | struct NonEmptyStruct(bool);
+   | ---------------------------- `NonEmptyStruct` defined here
+...
+LL |     match_false!(NonEmptyStruct(true));
+   |                  ^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct(_)` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
+  --> $DIR/match-empty-exhaustive_patterns.rs:83:18
+   |
+LL | / union NonEmptyUnion1 {
+LL | |     foo: (),
+LL | | }
+   | |_- `NonEmptyUnion1` defined here
+...
+LL |       match_false!((NonEmptyUnion1 { foo: () }));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
+  --> $DIR/match-empty-exhaustive_patterns.rs:85:18
+   |
+LL | / union NonEmptyUnion2 {
+LL | |     foo: (),
+LL | |     bar: (),
+LL | | }
+   | |_- `NonEmptyUnion2` defined here
+...
+LL |       match_false!((NonEmptyUnion2 { foo: () }));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
+  --> $DIR/match-empty-exhaustive_patterns.rs:87:18
+   |
+LL | / enum NonEmptyEnum1 {
+LL | |     Foo(bool),
+   | |     --- not covered
+LL | |
+LL | |
+LL | | }
+   | |_- `NonEmptyEnum1` defined here
+...
+LL |       match_false!(NonEmptyEnum1::Foo(true));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
+  --> $DIR/match-empty-exhaustive_patterns.rs:89:18
+   |
+LL | / enum NonEmptyEnum2 {
+LL | |     Foo(bool),
+   | |     --- not covered
+LL | |
+LL | |
+LL | |     Bar,
+   | |     --- not covered
+LL | |
+LL | |
+LL | | }
+   | |_- `NonEmptyEnum2` defined here
+...
+LL |       match_false!(NonEmptyEnum2::Foo(true));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
+  --> $DIR/match-empty-exhaustive_patterns.rs:91:18
+   |
+LL | / enum NonEmptyEnum5 {
+LL | |     V1, V2, V3, V4, V5,
+LL | | }
+   | |_- `NonEmptyEnum5` defined here
+...
+LL |       match_false!(NonEmptyEnum5::V1);
+   |                    ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error: aborting due to 18 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/pattern/usefulness/match-empty.rs b/src/test/ui/pattern/usefulness/match-empty.rs
new file mode 100644
index 0000000..f757712
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/match-empty.rs
@@ -0,0 +1,92 @@
+#![feature(never_type)]
+#![deny(unreachable_patterns)]
+enum Foo {}
+
+struct NonEmptyStruct(bool); //~ `NonEmptyStruct` defined here
+union NonEmptyUnion1 { //~ `NonEmptyUnion1` defined here
+    foo: (),
+}
+union NonEmptyUnion2 { //~ `NonEmptyUnion2` defined here
+    foo: (),
+    bar: (),
+}
+enum NonEmptyEnum1 { //~ `NonEmptyEnum1` defined here
+    Foo(bool),
+    //~^ not covered
+    //~| not covered
+}
+enum NonEmptyEnum2 { //~ `NonEmptyEnum2` defined here
+    Foo(bool),
+    //~^ not covered
+    //~| not covered
+    Bar,
+    //~^ not covered
+    //~| not covered
+}
+enum NonEmptyEnum5 { //~ `NonEmptyEnum5` defined here
+    V1, V2, V3, V4, V5,
+}
+
+macro_rules! match_empty {
+    ($e:expr) => {
+        match $e {}
+    };
+}
+macro_rules! match_false {
+    ($e:expr) => {
+        match $e {
+            _ if false => {}
+        }
+    };
+}
+
+fn foo(x: Foo) {
+    match_empty!(x); // ok
+    match_false!(x); // Not detected as unreachable nor exhaustive.
+    //~^ ERROR non-exhaustive patterns: `_` not covered
+    match x {
+        _ => {}, // Not detected as unreachable, see #55123.
+    }
+}
+
+fn main() {
+    // `exhaustive_patterns` is not on, so uninhabited branches are not detected as unreachable.
+    match None::<!> {
+        None => {}
+        Some(_) => {}
+    }
+    match None::<Foo> {
+        None => {}
+        Some(_) => {}
+    }
+
+    match_empty!(0u8);
+    //~^ ERROR type `u8` is non-empty
+    match_empty!(NonEmptyStruct(true));
+    //~^ ERROR type `NonEmptyStruct` is non-empty
+    match_empty!((NonEmptyUnion1 { foo: () }));
+    //~^ ERROR type `NonEmptyUnion1` is non-empty
+    match_empty!((NonEmptyUnion2 { foo: () }));
+    //~^ ERROR type `NonEmptyUnion2` is non-empty
+    match_empty!(NonEmptyEnum1::Foo(true));
+    //~^ ERROR `Foo(_)` not covered
+    match_empty!(NonEmptyEnum2::Foo(true));
+    //~^ ERROR `Foo(_)` and `Bar` not covered
+    match_empty!(NonEmptyEnum5::V1);
+    //~^ ERROR `V1`, `V2`, `V3` and 2 more not covered
+
+    match_false!(0u8);
+    //~^ ERROR `_` not covered
+    match_false!(NonEmptyStruct(true));
+    //~^ ERROR `NonEmptyStruct(_)` not covered
+    match_false!((NonEmptyUnion1 { foo: () }));
+    //~^ ERROR `NonEmptyUnion1 { .. }` not covered
+    match_false!((NonEmptyUnion2 { foo: () }));
+    //~^ ERROR `NonEmptyUnion2 { .. }` not covered
+    match_false!(NonEmptyEnum1::Foo(true));
+    //~^ ERROR `Foo(_)` not covered
+    match_false!(NonEmptyEnum2::Foo(true));
+    //~^ ERROR `Foo(_)` and `Bar` not covered
+    match_false!(NonEmptyEnum5::V1);
+    //~^ ERROR `V1`, `V2`, `V3` and 2 more not covered
+}
diff --git a/src/test/ui/pattern/usefulness/match-empty.stderr b/src/test/ui/pattern/usefulness/match-empty.stderr
new file mode 100644
index 0000000..72e3fc0
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/match-empty.stderr
@@ -0,0 +1,204 @@
+error[E0004]: non-exhaustive patterns: `_` not covered
+  --> $DIR/match-empty.rs:45:18
+   |
+LL | enum Foo {}
+   | ----------- `Foo` defined here
+...
+LL |     match_false!(x); // Not detected as unreachable nor exhaustive.
+   |                  ^ pattern `_` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: type `u8` is non-empty
+  --> $DIR/match-empty.rs:63:18
+   |
+LL |     match_empty!(0u8);
+   |                  ^^^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyStruct` is non-empty
+  --> $DIR/match-empty.rs:65:18
+   |
+LL | struct NonEmptyStruct(bool);
+   | ---------------------------- `NonEmptyStruct` defined here
+...
+LL |     match_empty!(NonEmptyStruct(true));
+   |                  ^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
+  --> $DIR/match-empty.rs:67:18
+   |
+LL | / union NonEmptyUnion1 {
+LL | |     foo: (),
+LL | | }
+   | |_- `NonEmptyUnion1` defined here
+...
+LL |       match_empty!((NonEmptyUnion1 { foo: () }));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
+  --> $DIR/match-empty.rs:69:18
+   |
+LL | / union NonEmptyUnion2 {
+LL | |     foo: (),
+LL | |     bar: (),
+LL | | }
+   | |_- `NonEmptyUnion2` defined here
+...
+LL |       match_empty!((NonEmptyUnion2 { foo: () }));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
+  --> $DIR/match-empty.rs:71:18
+   |
+LL | / enum NonEmptyEnum1 {
+LL | |     Foo(bool),
+   | |     --- not covered
+LL | |
+LL | |
+LL | | }
+   | |_- `NonEmptyEnum1` defined here
+...
+LL |       match_empty!(NonEmptyEnum1::Foo(true));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
+  --> $DIR/match-empty.rs:73:18
+   |
+LL | / enum NonEmptyEnum2 {
+LL | |     Foo(bool),
+   | |     --- not covered
+LL | |
+LL | |
+LL | |     Bar,
+   | |     --- not covered
+LL | |
+LL | |
+LL | | }
+   | |_- `NonEmptyEnum2` defined here
+...
+LL |       match_empty!(NonEmptyEnum2::Foo(true));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
+  --> $DIR/match-empty.rs:75:18
+   |
+LL | / enum NonEmptyEnum5 {
+LL | |     V1, V2, V3, V4, V5,
+LL | | }
+   | |_- `NonEmptyEnum5` defined here
+...
+LL |       match_empty!(NonEmptyEnum5::V1);
+   |                    ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+  --> $DIR/match-empty.rs:78:18
+   |
+LL |     match_false!(0u8);
+   |                  ^^^ pattern `_` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `NonEmptyStruct(_)` not covered
+  --> $DIR/match-empty.rs:80:18
+   |
+LL | struct NonEmptyStruct(bool);
+   | ---------------------------- `NonEmptyStruct` defined here
+...
+LL |     match_false!(NonEmptyStruct(true));
+   |                  ^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct(_)` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
+  --> $DIR/match-empty.rs:82:18
+   |
+LL | / union NonEmptyUnion1 {
+LL | |     foo: (),
+LL | | }
+   | |_- `NonEmptyUnion1` defined here
+...
+LL |       match_false!((NonEmptyUnion1 { foo: () }));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
+  --> $DIR/match-empty.rs:84:18
+   |
+LL | / union NonEmptyUnion2 {
+LL | |     foo: (),
+LL | |     bar: (),
+LL | | }
+   | |_- `NonEmptyUnion2` defined here
+...
+LL |       match_false!((NonEmptyUnion2 { foo: () }));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
+  --> $DIR/match-empty.rs:86:18
+   |
+LL | / enum NonEmptyEnum1 {
+LL | |     Foo(bool),
+   | |     --- not covered
+LL | |
+LL | |
+LL | | }
+   | |_- `NonEmptyEnum1` defined here
+...
+LL |       match_false!(NonEmptyEnum1::Foo(true));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
+  --> $DIR/match-empty.rs:88:18
+   |
+LL | / enum NonEmptyEnum2 {
+LL | |     Foo(bool),
+   | |     --- not covered
+LL | |
+LL | |
+LL | |     Bar,
+   | |     --- not covered
+LL | |
+LL | |
+LL | | }
+   | |_- `NonEmptyEnum2` defined here
+...
+LL |       match_false!(NonEmptyEnum2::Foo(true));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
+  --> $DIR/match-empty.rs:90:18
+   |
+LL | / enum NonEmptyEnum5 {
+LL | |     V1, V2, V3, V4, V5,
+LL | | }
+   | |_- `NonEmptyEnum5` defined here
+...
+LL |       match_false!(NonEmptyEnum5::V1);
+   |                    ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error: aborting due to 15 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs
index bbc25d4..8516baf 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs
@@ -6,3 +6,6 @@
     Tuple(u32),
     Struct { field: u32 }
 }
+
+#[non_exhaustive]
+pub enum EmptyNonExhaustiveEnum {}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum.rs b/src/test/ui/rfc-2008-non-exhaustive/enum.rs
index 7423a97..802f20b 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/enum.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/enum.rs
@@ -1,7 +1,14 @@
 // aux-build:enums.rs
 extern crate enums;
 
-use enums::NonExhaustiveEnum;
+use enums::{EmptyNonExhaustiveEnum, NonExhaustiveEnum};
+
+fn empty(x: EmptyNonExhaustiveEnum) {
+    match x {} //~ ERROR type `enums::EmptyNonExhaustiveEnum` is non-empty
+    match x {
+        _ => {}, // ok
+    }
+}
 
 fn main() {
     let enum_unit = NonExhaustiveEnum::Unit;
@@ -13,6 +20,9 @@
         NonExhaustiveEnum::Struct { .. } => "third"
     };
 
+    match enum_unit {};
+    //~^ ERROR non-exhaustive patterns: `_` not covered [E0004]
+
     // Everything below this is expected to compile successfully.
 
     let enum_unit = NonExhaustiveEnum::Unit;
diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum.stderr b/src/test/ui/rfc-2008-non-exhaustive/enum.stderr
index b5c1a4e..a2bdcba 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/enum.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/enum.stderr
@@ -1,11 +1,27 @@
+error[E0004]: non-exhaustive patterns: type `enums::EmptyNonExhaustiveEnum` is non-empty
+  --> $DIR/enum.rs:7:11
+   |
+LL |     match x {}
+   |           ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
 error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/enum.rs:9:11
+  --> $DIR/enum.rs:16:11
    |
 LL |     match enum_unit {
    |           ^^^^^^^^^ pattern `_` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error: aborting due to previous error
+error[E0004]: non-exhaustive patterns: `_` not covered
+  --> $DIR/enum.rs:23:11
+   |
+LL |     match enum_unit {};
+   |           ^^^^^^^^^ pattern `_` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.rs b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.rs
new file mode 100644
index 0000000..afd6d99
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.rs
@@ -0,0 +1,37 @@
+#![deny(unreachable_patterns)]
+
+#[non_exhaustive]
+pub enum NonExhaustiveEnum {
+    Unit,
+    //~^ not covered
+    Tuple(u32),
+    //~^ not covered
+    Struct { field: u32 }
+    //~^ not covered
+}
+
+pub enum NormalEnum {
+    Unit,
+    //~^ not covered
+    Tuple(u32),
+    //~^ not covered
+    Struct { field: u32 }
+    //~^ not covered
+}
+
+#[non_exhaustive]
+pub enum EmptyNonExhaustiveEnum {}
+
+fn empty_non_exhaustive(x: EmptyNonExhaustiveEnum) {
+    match x {}
+    match x {
+        _ => {} // not detected as unreachable
+    }
+}
+
+fn main() {
+    match NonExhaustiveEnum::Unit {}
+    //~^ ERROR `Unit`, `Tuple(_)` and `Struct { .. }` not covered [E0004]
+    match NormalEnum::Unit {}
+    //~^ ERROR `Unit`, `Tuple(_)` and `Struct { .. }` not covered [E0004]
+}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr
new file mode 100644
index 0000000..a99a690
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr
@@ -0,0 +1,45 @@
+error[E0004]: non-exhaustive patterns: `Unit`, `Tuple(_)` and `Struct { .. }` not covered
+  --> $DIR/enum_same_crate_empty_match.rs:33:11
+   |
+LL | / pub enum NonExhaustiveEnum {
+LL | |     Unit,
+   | |     ---- not covered
+LL | |
+LL | |     Tuple(u32),
+   | |     ----- not covered
+LL | |
+LL | |     Struct { field: u32 }
+   | |     ------ not covered
+LL | |
+LL | | }
+   | |_- `NonExhaustiveEnum` defined here
+...
+LL |       match NonExhaustiveEnum::Unit {}
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ patterns `Unit`, `Tuple(_)` and `Struct { .. }` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `Unit`, `Tuple(_)` and `Struct { .. }` not covered
+  --> $DIR/enum_same_crate_empty_match.rs:35:11
+   |
+LL | / pub enum NormalEnum {
+LL | |     Unit,
+   | |     ---- not covered
+LL | |
+LL | |     Tuple(u32),
+   | |     ----- not covered
+LL | |
+LL | |     Struct { field: u32 }
+   | |     ------ not covered
+LL | |
+LL | | }
+   | |_- `NormalEnum` defined here
+...
+LL |       match NormalEnum::Unit {}
+   |             ^^^^^^^^^^^^^^^^ patterns `Unit`, `Tuple(_)` and `Struct { .. }` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr
index b903e9b..0d669a9a 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr
@@ -1,4 +1,4 @@
-error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedEnum` of type `uninhabited::IndirectUninhabitedEnum` is not handled
+error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedEnum` is non-empty
   --> $DIR/indirect_match.rs:18:11
    |
 LL |     match x {}
@@ -6,7 +6,7 @@
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedStruct` of type `uninhabited::IndirectUninhabitedStruct` is not handled
+error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedStruct` is non-empty
   --> $DIR/indirect_match.rs:22:11
    |
 LL |     match x {}
@@ -14,7 +14,7 @@
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedTupleStruct` of type `uninhabited::IndirectUninhabitedTupleStruct` is not handled
+error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedTupleStruct` is non-empty
   --> $DIR/indirect_match.rs:26:11
    |
 LL |     match x {}
@@ -22,7 +22,7 @@
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedVariants` of type `uninhabited::IndirectUninhabitedVariants` is not handled
+error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedVariants` is non-empty
   --> $DIR/indirect_match.rs:32:11
    |
 LL |     match x {}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr
index f94616d..41a37cf 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr
@@ -1,53 +1,41 @@
-error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedEnum` of type `IndirectUninhabitedEnum` is not handled
+error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedEnum` is non-empty
   --> $DIR/indirect_match_same_crate.rs:32:11
    |
 LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
-   | ----------------------------------------------------
-   | |          |
-   | |          variant not covered
-   | `IndirectUninhabitedEnum` defined here
+   | ---------------------------------------------------- `IndirectUninhabitedEnum` defined here
 ...
 LL |     match x {}
    |           ^
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedStruct` of type `IndirectUninhabitedStruct` is not handled
+error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-empty
   --> $DIR/indirect_match_same_crate.rs:36:11
    |
 LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
-   | --------------------------------------------------------
-   | |          |
-   | |          variant not covered
-   | `IndirectUninhabitedStruct` defined here
+   | -------------------------------------------------------- `IndirectUninhabitedStruct` defined here
 ...
 LL |     match x {}
    |           ^
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedTupleStruct` of type `IndirectUninhabitedTupleStruct` is not handled
+error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is non-empty
   --> $DIR/indirect_match_same_crate.rs:40:11
    |
 LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
-   | ------------------------------------------------------------------
-   | |          |
-   | |          variant not covered
-   | `IndirectUninhabitedTupleStruct` defined here
+   | ------------------------------------------------------------------ `IndirectUninhabitedTupleStruct` defined here
 ...
 LL |     match x {}
    |           ^
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedVariants` of type `IndirectUninhabitedVariants` is not handled
+error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non-empty
   --> $DIR/indirect_match_same_crate.rs:46:11
    |
 LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
-   | ------------------------------------------------------------
-   | |          |
-   | |          variant not covered
-   | `IndirectUninhabitedVariants` defined here
+   | ------------------------------------------------------------ `IndirectUninhabitedVariants` defined here
 ...
 LL |     match x {}
    |           ^
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr
index de3fa90..10a456a 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr
@@ -6,7 +6,7 @@
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error[E0004]: non-exhaustive patterns: pattern `UninhabitedStruct` of type `uninhabited::UninhabitedStruct` is not handled
+error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedStruct` is non-empty
   --> $DIR/match.rs:22:11
    |
 LL |     match x {}
@@ -14,7 +14,7 @@
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error[E0004]: non-exhaustive patterns: pattern `UninhabitedTupleStruct` of type `uninhabited::UninhabitedTupleStruct` is not handled
+error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedTupleStruct` is non-empty
   --> $DIR/match.rs:26:11
    |
 LL |     match x {}
@@ -22,11 +22,11 @@
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error[E0004]: non-exhaustive patterns: multiple patterns of type `uninhabited::UninhabitedVariants` are not handled
+error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered
   --> $DIR/match.rs:30:11
    |
 LL |     match x {}
-   |           ^
+   |           ^ patterns `Tuple(_)` and `Struct { .. }` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr
index 3dd1a91..148af8c 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr
@@ -1,10 +1,7 @@
-error[E0004]: non-exhaustive patterns: pattern `UninhabitedStruct` of type `UninhabitedStruct` is not handled
+error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty
   --> $DIR/match_same_crate.rs:28:11
    |
-LL |   pub struct UninhabitedStruct {
-   |   -          ----------------- variant not covered
-   |  _|
-   | |
+LL | / pub struct UninhabitedStruct {
 LL | |     _priv: !,
 LL | | }
    | |_- `UninhabitedStruct` defined here
@@ -14,33 +11,30 @@
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error[E0004]: non-exhaustive patterns: pattern `UninhabitedTupleStruct` of type `UninhabitedTupleStruct` is not handled
+error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty
   --> $DIR/match_same_crate.rs:32:11
    |
 LL | pub struct UninhabitedTupleStruct(!);
-   | -------------------------------------
-   | |          |
-   | |          variant not covered
-   | `UninhabitedTupleStruct` defined here
+   | ------------------------------------- `UninhabitedTupleStruct` defined here
 ...
 LL |     match x {}
    |           ^
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error[E0004]: non-exhaustive patterns: multiple patterns of type `UninhabitedVariants` are not handled
+error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered
   --> $DIR/match_same_crate.rs:36:11
    |
 LL | / pub enum UninhabitedVariants {
 LL | |     #[non_exhaustive] Tuple(!),
-   | |                       ----- variant not covered
+   | |                       ----- not covered
 LL | |     #[non_exhaustive] Struct { x: ! }
-   | |                       ------ variant not covered
+   | |                       ------ not covered
 LL | | }
    | |_- `UninhabitedVariants` defined here
 ...
 LL |       match x {}
-   |             ^
+   |             ^ patterns `Tuple(_)` and `Struct { .. }` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr
index 3b56c68..2fc09c8 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr
@@ -22,11 +22,11 @@
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedVariants` is non-empty
+error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered
   --> $DIR/match_with_exhaustive_patterns.rs:33:11
    |
 LL |     match x {}
-   |           ^
+   |           ^ patterns `Tuple(_)` and `Struct { .. }` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
diff --git a/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr b/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr
index 7af6075..18ffdcc 100644
--- a/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr
+++ b/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr
@@ -9,6 +9,9 @@
 error[E0004]: non-exhaustive patterns: type `&Void` is non-empty
   --> $DIR/uninhabited-matches-feature-gated.rs:12:19
    |
+LL | enum Void {}
+   | ------------ `Void` defined here
+...
 LL |     let _ = match x {};
    |                   ^
    |
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 7b928a2..36e4129 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -135,6 +135,7 @@
     Crate("polonius-engine"),
     Crate("ppv-lite86"),
     Crate("proc-macro2"),
+    Crate("punycode"),
     Crate("quick-error"),
     Crate("quote"),
     Crate("rand"),