about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-12-11 09:12:06 +0000
committerbors <bors@rust-lang.org>2019-12-11 09:12:06 +0000
commit033662dfbca088937b9cdfd3d9584015b5e375b2 (patch)
tree2ef62b3f6d4746ca251307c5543a7f066ada1fa3 /src
parentddca1e09c36a6ce21d95fec1619f23ba59b69c8a (diff)
parentf6ceef546b9b008afd12fafa742783c570a18aa8 (diff)
downloadrust-033662dfbca088937b9cdfd3d9584015b5e375b2.tar.gz
rust-033662dfbca088937b9cdfd3d9584015b5e375b2.zip
Auto merge of #67220 - Centril:rollup-n3u9wd5, r=Centril
Rollup of 6 pull requests

Successful merges:

 - #66881 (Optimize Ord trait implementation for bool)
 - #67015 (Fix constant propagation for scalar pairs)
 - #67074 (Add options to --extern flag.)
 - #67164 (Ensure that panicking in constants eventually errors)
 - #67174 (Remove `checked_add` in `Layout::repeat`)
 - #67205 (Make `publish_toolstate.sh` executable)

Failed merges:

r? @ghost
Diffstat (limited to 'src')
-rwxr-xr-x[-rw-r--r--]src/ci/publish_toolstate.sh0
-rw-r--r--src/libcore/alloc.rs7
-rw-r--r--src/libcore/cmp.rs12
-rw-r--r--src/libcore/tests/cmp.rs8
-rw-r--r--src/librustc_interface/tests.rs23
-rw-r--r--src/librustc_metadata/creader.rs15
-rw-r--r--src/librustc_metadata/locator.rs5
-rw-r--r--src/librustc_mir/build/expr/into.rs9
-rw-r--r--src/librustc_mir/transform/const_prop.rs48
-rw-r--r--src/librustc_resolve/lib.rs6
-rw-r--r--src/librustc_session/config.rs169
-rw-r--r--src/librustc_target/abi/mod.rs8
-rw-r--r--src/librustdoc/config.rs33
-rw-r--r--src/librustdoc/core.rs4
-rw-r--r--src/librustdoc/lib.rs4
-rw-r--r--src/test/codegen/bool-cmp.rs17
-rw-r--r--src/test/mir-opt/const_prop/issue-66971.rs38
-rw-r--r--src/test/mir-opt/const_prop/issue-67019.rs34
-rw-r--r--src/test/mir-opt/retain-never-const.rs28
-rw-r--r--src/test/rustdoc/issue-66159.rs3
-rw-r--r--src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs18
-rw-r--r--src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr22
-rw-r--r--src/test/ui/consts/const-eval/panic-assoc-never-type.rs15
-rw-r--r--src/test/ui/consts/const-eval/panic-assoc-never-type.stderr24
-rw-r--r--src/test/ui/consts/const-eval/panic-never-type.rs11
-rw-r--r--src/test/ui/consts/const-eval/panic-never-type.stderr24
-rw-r--r--src/test/ui/extern-flag/auxiliary/somedep.rs3
-rw-r--r--src/test/ui/extern-flag/multiple-opts.rs20
-rw-r--r--src/test/ui/extern-flag/multiple-opts.stderr9
-rw-r--r--src/test/ui/extern-flag/noprelude-and-prelude.rs10
-rw-r--r--src/test/ui/extern-flag/noprelude-resolves.rs11
-rw-r--r--src/test/ui/extern-flag/noprelude.rs7
-rw-r--r--src/test/ui/extern-flag/noprelude.stderr9
-rw-r--r--src/test/ui/extern-flag/public-and-private.rs13
-rw-r--r--src/test/ui/extern-flag/public-and-private.stderr14
-rw-r--r--src/test/ui/mir/issue66339.rs13
-rw-r--r--src/test/ui/privacy/pub-priv-dep/pub-priv1.rs5
-rw-r--r--src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr8
-rw-r--r--src/tools/compiletest/src/header.rs29
-rw-r--r--src/tools/compiletest/src/runtest.rs159
40 files changed, 684 insertions, 211 deletions
diff --git a/src/ci/publish_toolstate.sh b/src/ci/publish_toolstate.sh
index d8ff7407822..d8ff7407822 100644..100755
--- a/src/ci/publish_toolstate.sh
+++ b/src/ci/publish_toolstate.sh
diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs
index 4cfd6527deb..5c24e3d8f5d 100644
--- a/src/libcore/alloc.rs
+++ b/src/libcore/alloc.rs
@@ -239,8 +239,11 @@ impl Layout {
     #[unstable(feature = "alloc_layout_extra", issue = "55724")]
     #[inline]
     pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutErr> {
-        let padded_size = self.size().checked_add(self.padding_needed_for(self.align()))
-            .ok_or(LayoutErr { private: () })?;
+        // This cannot overflow. Quoting from the invariant of Layout:
+        // > `size`, when rounded up to the nearest multiple of `align`,
+        // > must not overflow (i.e., the rounded value must be less than
+        // > `usize::MAX`)
+        let padded_size = self.size() + self.padding_needed_for(self.align());
         let alloc_size = padded_size.checked_mul(n)
             .ok_or(LayoutErr { private: () })?;
 
diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs
index a5f355cd9a7..fd4be02e20f 100644
--- a/src/libcore/cmp.rs
+++ b/src/libcore/cmp.rs
@@ -1005,6 +1005,7 @@ pub fn max_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T {
 
 // Implementation of PartialEq, Eq, PartialOrd and Ord for primitive types
 mod impls {
+    use crate::hint::unreachable_unchecked;
     use crate::cmp::Ordering::{self, Less, Greater, Equal};
 
     macro_rules! partial_eq_impl {
@@ -1125,7 +1126,16 @@ mod impls {
     impl Ord for bool {
         #[inline]
         fn cmp(&self, other: &bool) -> Ordering {
-            (*self as u8).cmp(&(*other as u8))
+            // Casting to i8's and converting the difference to an Ordering generates
+            // more optimal assembly.
+            // See <https://github.com/rust-lang/rust/issues/66780> for more info.
+            match (*self as i8) - (*other as i8) {
+                -1 => Less,
+                0 => Equal,
+                1 => Greater,
+                // SAFETY: bool as i8 returns 0 or 1, so the difference can't be anything else
+                _ => unsafe { unreachable_unchecked() },
+            }
         }
     }
 
diff --git a/src/libcore/tests/cmp.rs b/src/libcore/tests/cmp.rs
index 5e6778e222a..56a2f4acf6e 100644
--- a/src/libcore/tests/cmp.rs
+++ b/src/libcore/tests/cmp.rs
@@ -10,6 +10,14 @@ fn test_int_totalord() {
 }
 
 #[test]
+fn test_bool_totalord() {
+    assert_eq!(true.cmp(&false), Greater);
+    assert_eq!(false.cmp(&true), Less);
+    assert_eq!(true.cmp(&true), Equal);
+    assert_eq!(false.cmp(&false), Equal);
+}
+
+#[test]
 fn test_mut_int_totalord() {
     assert_eq!((&mut 5).cmp(&&mut 10), Less);
     assert_eq!((&mut 10).cmp(&&mut 5), Greater);
diff --git a/src/librustc_interface/tests.rs b/src/librustc_interface/tests.rs
index 4c630b56cb4..d4b5e833dfb 100644
--- a/src/librustc_interface/tests.rs
+++ b/src/librustc_interface/tests.rs
@@ -7,7 +7,7 @@ use rustc::middle::cstore;
 use rustc::session::config::{build_configuration, build_session_options, to_crate_config};
 use rustc::session::config::{LtoCli, LinkerPluginLto, SwitchWithOptPath, ExternEntry};
 use rustc::session::config::{Externs, OutputType, OutputTypes, SymbolManglingVersion};
-use rustc::session::config::{rustc_optgroups, Options, ErrorOutputType, Passes};
+use rustc::session::config::{rustc_optgroups, Options, ErrorOutputType, Passes, ExternLocation};
 use rustc::session::{build_session, Session};
 use rustc::session::search_paths::SearchPath;
 use std::collections::{BTreeMap, BTreeSet};
@@ -38,14 +38,15 @@ fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) {
 fn new_public_extern_entry<S, I>(locations: I) -> ExternEntry
 where
     S: Into<String>,
-    I: IntoIterator<Item = Option<S>>,
+    I: IntoIterator<Item = S>,
 {
-    let locations: BTreeSet<_> = locations.into_iter().map(|o| o.map(|s| s.into()))
+    let locations: BTreeSet<_> = locations.into_iter().map(|s| s.into())
         .collect();
 
     ExternEntry {
-        locations,
-        is_private_dep: false
+        location: ExternLocation::ExactPaths(locations),
+        is_private_dep: false,
+        add_prelude: true,
     }
 }
 
@@ -160,33 +161,33 @@ fn test_externs_tracking_hash_different_construction_order() {
     v1.externs = Externs::new(mk_map(vec![
         (
             String::from("a"),
-            new_public_extern_entry(vec![Some("b"), Some("c")])
+            new_public_extern_entry(vec!["b", "c"])
         ),
         (
             String::from("d"),
-            new_public_extern_entry(vec![Some("e"), Some("f")])
+            new_public_extern_entry(vec!["e", "f"])
         ),
     ]));
 
     v2.externs = Externs::new(mk_map(vec![
         (
             String::from("d"),
-            new_public_extern_entry(vec![Some("e"), Some("f")])
+            new_public_extern_entry(vec!["e", "f"])
         ),
         (
             String::from("a"),
-            new_public_extern_entry(vec![Some("b"), Some("c")])
+            new_public_extern_entry(vec!["b", "c"])
         ),
     ]));
 
     v3.externs = Externs::new(mk_map(vec![
         (
             String::from("a"),
-            new_public_extern_entry(vec![Some("b"), Some("c")])
+            new_public_extern_entry(vec!["b", "c"])
         ),
         (
             String::from("d"),
-            new_public_extern_entry(vec![Some("f"), Some("e")])
+            new_public_extern_entry(vec!["f", "e"])
         ),
     ]));
 
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 25bd2c45da5..0a0f2560b99 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -218,13 +218,14 @@ impl<'a> CrateLoader<'a> {
             let source = self.cstore.get_crate_data(cnum).source();
             if let Some(entry) = self.sess.opts.externs.get(&name.as_str()) {
                 // Only use `--extern crate_name=path` here, not `--extern crate_name`.
-                let found = entry.locations.iter().filter_map(|l| l.as_ref()).any(|l| {
-                    let l = fs::canonicalize(l).ok();
-                    source.dylib.as_ref().map(|p| &p.0) == l.as_ref() ||
-                    source.rlib.as_ref().map(|p| &p.0) == l.as_ref()
-                });
-                if found {
-                    ret = Some(cnum);
+                if let Some(mut files) = entry.files() {
+                    if files.any(|l| {
+                        let l = fs::canonicalize(l).ok();
+                        source.dylib.as_ref().map(|p| &p.0) == l.as_ref() ||
+                        source.rlib.as_ref().map(|p| &p.0) == l.as_ref()
+                    }) {
+                        ret = Some(cnum);
+                    }
                 }
                 return
             }
diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs
index c6fb80eca05..8a1eeea0251 100644
--- a/src/librustc_metadata/locator.rs
+++ b/src/librustc_metadata/locator.rs
@@ -328,8 +328,9 @@ impl<'a> CrateLocator<'a> {
             crate_name,
             exact_paths: if hash.is_none() {
                 sess.opts.externs.get(&crate_name.as_str()).into_iter()
-                    .flat_map(|entry| entry.locations.iter())
-                    .filter_map(|location| location.clone().map(PathBuf::from)).collect()
+                    .filter_map(|entry| entry.files())
+                    .flatten()
+                    .map(|location| PathBuf::from(location)).collect()
             } else {
                 // SVH being specified means this is a transitive dependency,
                 // so `--extern` options do not apply.
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs
index f5dc09ccebc..07a44b190b2 100644
--- a/src/librustc_mir/build/expr/into.rs
+++ b/src/librustc_mir/build/expr/into.rs
@@ -65,7 +65,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     _ => false,
                 };
 
-                unpack!(block = this.as_local_rvalue(block, source));
+                // (#66975) Source could be a const of type `!`, so has to
+                // exist in the generated MIR.
+                unpack!(block = this.as_temp(
+                    block,
+                    this.local_scope(),
+                    source,
+                    Mutability::Mut,
+                ));
 
                 // This is an optimization. If the expression was a call then we already have an
                 // unreachable block. Don't bother to terminate it and create a new one.
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index 884312514e4..aff91ac5af9 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -636,19 +636,45 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                     ScalarMaybeUndef::Scalar(one),
                     ScalarMaybeUndef::Scalar(two)
                 ) => {
+                    // Found a value represented as a pair. For now only do cont-prop if type of
+                    // Rvalue is also a pair with two scalars. The more general case is more
+                    // complicated to implement so we'll do it later.
                     let ty = &value.layout.ty.kind;
+                    // Only do it for tuples
                     if let ty::Tuple(substs) = ty {
-                        *rval = Rvalue::Aggregate(
-                            Box::new(AggregateKind::Tuple),
-                            vec![
-                                self.operand_from_scalar(
-                                    one, substs[0].expect_ty(), source_info.span
-                                ),
-                                self.operand_from_scalar(
-                                    two, substs[1].expect_ty(), source_info.span
-                                ),
-                            ],
-                        );
+                        // Only do it if tuple is also a pair with two scalars
+                        if substs.len() == 2 {
+                            let opt_ty1_ty2 = self.use_ecx(source_info, |this| {
+                                let ty1 = substs[0].expect_ty();
+                                let ty2 = substs[1].expect_ty();
+                                let ty_is_scalar = |ty| {
+                                    this.ecx
+                                        .layout_of(ty)
+                                        .ok()
+                                        .map(|ty| ty.details.abi.is_scalar())
+                                        == Some(true)
+                                };
+                                if ty_is_scalar(ty1) && ty_is_scalar(ty2) {
+                                    Ok(Some((ty1, ty2)))
+                                } else {
+                                    Ok(None)
+                                }
+                            });
+
+                            if let Some(Some((ty1, ty2))) = opt_ty1_ty2 {
+                                *rval = Rvalue::Aggregate(
+                                    Box::new(AggregateKind::Tuple),
+                                    vec![
+                                        self.operand_from_scalar(
+                                            one, ty1, source_info.span
+                                        ),
+                                        self.operand_from_scalar(
+                                            two, ty2, source_info.span
+                                        ),
+                                    ],
+                                );
+                            }
+                        }
                     }
                 },
                 _ => { }
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 9db89c8273d..d3656248b1b 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -1136,8 +1136,10 @@ impl<'a> Resolver<'a> {
         definitions.create_root_def(crate_name, session.local_crate_disambiguator());
 
         let mut extern_prelude: FxHashMap<Ident, ExternPreludeEntry<'_>> =
-            session.opts.externs.iter().map(|kv| (Ident::from_str(kv.0), Default::default()))
-                                       .collect();
+            session.opts.externs.iter()
+                .filter(|(_, entry)| entry.add_prelude)
+                .map(|(name, _)| (Ident::from_str(name), Default::default()))
+                .collect();
 
         if !attr::contains_name(&krate.attrs, sym::no_core) {
             extern_prelude.insert(Ident::with_dummy_span(sym::core), Default::default());
diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs
index 58113bb8cd6..7f3bab8f232 100644
--- a/src/librustc_session/config.rs
+++ b/src/librustc_session/config.rs
@@ -1,3 +1,5 @@
+// ignore-tidy-filelength
+
 //! Contains infrastructure for configuring the compiler, including parsing
 //! command-line options.
 
@@ -31,7 +33,7 @@ use std::fmt;
 use std::str::{self, FromStr};
 use std::hash::Hasher;
 use std::collections::hash_map::DefaultHasher;
-use std::iter::FromIterator;
+use std::iter::{self, FromIterator};
 use std::path::{Path, PathBuf};
 
 pub struct Config {
@@ -322,10 +324,35 @@ impl OutputTypes {
 #[derive(Clone)]
 pub struct Externs(BTreeMap<String, ExternEntry>);
 
-#[derive(Clone, Debug, Default)]
+#[derive(Clone, Debug)]
 pub struct ExternEntry {
-    pub locations: BTreeSet<Option<String>>,
-    pub is_private_dep: bool
+    pub location: ExternLocation,
+    /// Indicates this is a "private" dependency for the
+    /// `exported_private_dependencies` lint.
+    ///
+    /// This can be set with the `priv` option like
+    /// `--extern priv:name=foo.rlib`.
+    pub is_private_dep: bool,
+    /// Add the extern entry to the extern prelude.
+    ///
+    /// This can be disabled with the `noprelude` option like
+    /// `--extern noprelude:name`.
+    pub add_prelude: bool,
+}
+
+#[derive(Clone, Debug)]
+pub enum ExternLocation {
+    /// Indicates to look for the library in the search paths.
+    ///
+    /// Added via `--extern name`.
+    FoundInLibrarySearchDirectories,
+    /// The locations where this extern entry must be found.
+    ///
+    /// The `CrateLoader` is responsible for loading these and figuring out
+    /// which one to use.
+    ///
+    /// Added via `--extern prelude_name=some_file.rlib`
+    ExactPaths(BTreeSet<String>),
 }
 
 impl Externs {
@@ -342,6 +369,18 @@ impl Externs {
     }
 }
 
+impl ExternEntry {
+    fn new(location: ExternLocation) -> ExternEntry {
+        ExternEntry { location, is_private_dep: false, add_prelude: false }
+    }
+
+    pub fn files(&self) -> Option<impl Iterator<Item = &String>> {
+        match &self.location {
+            ExternLocation::ExactPaths(set) => Some(set.iter()),
+            _ => None,
+        }
+    }
+}
 
 macro_rules! hash_option {
     ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [UNTRACKED]) => ({});
@@ -1869,12 +1908,6 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
             "Specify where an external rust library is located",
             "NAME[=PATH]",
         ),
-        opt::multi_s(
-            "",
-            "extern-private",
-            "Specify where an extern rust library is located, marking it as a private dependency",
-            "NAME=PATH",
-        ),
         opt::opt_s("", "sysroot", "Override the system root", "PATH"),
         opt::multi("Z", "", "Set internal debugging options", "FLAG"),
         opt::opt_s(
@@ -2435,43 +2468,105 @@ fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType)
     }
 }
 
-fn parse_externs(
+pub fn parse_externs(
     matches: &getopts::Matches,
     debugging_opts: &DebuggingOptions,
     error_format: ErrorOutputType,
 ) -> Externs {
-    if matches.opt_present("extern-private") && !debugging_opts.unstable_options {
-        early_error(
-            ErrorOutputType::default(),
-            "'--extern-private' is unstable and only \
-            available for nightly builds of rustc."
-        )
-    }
-
-    // We start out with a `Vec<(Option<String>, bool)>>`,
-    // and later convert it into a `BTreeSet<(Option<String>, bool)>`
-    // This allows to modify entries in-place to set their correct
-    // 'public' value.
+    let is_unstable_enabled = debugging_opts.unstable_options;
     let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
-    for (arg, private) in matches.opt_strs("extern").into_iter().map(|v| (v, false))
-        .chain(matches.opt_strs("extern-private").into_iter().map(|v| (v, true))) {
-
+    for arg in matches.opt_strs("extern") {
         let mut parts = arg.splitn(2, '=');
-        let name = parts.next().unwrap_or_else(||
-            early_error(error_format, "--extern value must not be empty"));
-        let location = parts.next().map(|s| s.to_string());
+        let name = parts
+            .next()
+            .unwrap_or_else(|| early_error(error_format, "--extern value must not be empty"));
+        let path = parts.next().map(|s| s.to_string());
+
+        let mut name_parts = name.splitn(2, ':');
+        let first_part = name_parts.next();
+        let second_part = name_parts.next();
+        let (options, name) = match (first_part, second_part) {
+            (Some(opts), Some(name)) => (Some(opts), name),
+            (Some(name), None) => (None, name),
+            (None, None) => early_error(error_format, "--extern name must not be empty"),
+            _ => unreachable!(),
+        };
+
+        let entry = externs.entry(name.to_owned());
 
-        let entry = externs
-            .entry(name.to_owned())
-            .or_default();
+        use std::collections::btree_map::Entry;
 
+        let entry = if let Some(path) = path {
+            // --extern prelude_name=some_file.rlib
+            match entry {
+                Entry::Vacant(vacant) => {
+                    let files = BTreeSet::from_iter(iter::once(path));
+                    vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
+                }
+                Entry::Occupied(occupied) => {
+                    let ext_ent = occupied.into_mut();
+                    match ext_ent {
+                        ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
+                            files.insert(path);
+                        }
+                        ExternEntry {
+                            location: location @ ExternLocation::FoundInLibrarySearchDirectories,
+                            ..
+                        } => {
+                            // Exact paths take precedence over search directories.
+                            let files = BTreeSet::from_iter(iter::once(path));
+                            *location = ExternLocation::ExactPaths(files);
+                        }
+                    }
+                    ext_ent
+                }
+            }
+        } else {
+            // --extern prelude_name
+            match entry {
+                Entry::Vacant(vacant) => {
+                    vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
+                }
+                Entry::Occupied(occupied) => {
+                    // Ignore if already specified.
+                    occupied.into_mut()
+                }
+            }
+        };
 
-        entry.locations.insert(location.clone());
+        let mut is_private_dep = false;
+        let mut add_prelude = true;
+        if let Some(opts) = options {
+            if !is_unstable_enabled {
+                early_error(
+                    error_format,
+                    "the `-Z unstable-options` flag must also be passed to \
+                     enable `--extern options",
+                );
+            }
+            for opt in opts.split(',') {
+                match opt {
+                    "priv" => is_private_dep = true,
+                    "noprelude" => {
+                        if let ExternLocation::ExactPaths(_) = &entry.location {
+                            add_prelude = false;
+                        } else {
+                            early_error(
+                                error_format,
+                                "the `noprelude` --extern option requires a file path",
+                            );
+                        }
+                    }
+                    _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
+                }
+            }
+        }
 
-        // Crates start out being not private,
-        // and go to being private if we see an '--extern-private'
-        // flag
-        entry.is_private_dep |= private;
+        // Crates start out being not private, and go to being private `priv`
+        // is specified.
+        entry.is_private_dep |= is_private_dep;
+        // If any flag is missing `noprelude`, then add to the prelude.
+        entry.add_prelude |= add_prelude;
     }
     Externs(externs)
 }
diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs
index ac781819cc3..b0bc0529297 100644
--- a/src/librustc_target/abi/mod.rs
+++ b/src/librustc_target/abi/mod.rs
@@ -802,6 +802,14 @@ impl Abi {
             _ => false,
         }
     }
+
+    /// Returns `true` is this is a scalar type
+    pub fn is_scalar(&self) -> bool {
+        match *self {
+            Abi::Scalar(_) => true,
+            _ => false,
+        }
+    }
 }
 
 rustc_index::newtype_index! {
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index cdb1a1f6997..0db3d28bf0e 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -7,10 +7,10 @@ use errors;
 use getopts;
 use rustc::lint::Level;
 use rustc::session;
-use rustc::session::config::{CrateType, parse_crate_types_from_list};
+use rustc::session::config::{CrateType, parse_crate_types_from_list, parse_externs};
 use rustc::session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs};
 use rustc::session::config::{nightly_options, build_codegen_options, build_debugging_options,
-                             get_cmd_lint_options, host_triple, ExternEntry};
+                             get_cmd_lint_options, host_triple};
 use rustc::session::search_paths::SearchPath;
 use rustc_driver;
 use rustc_target::spec::TargetTriple;
@@ -320,13 +320,7 @@ impl Options {
         let libs = matches.opt_strs("L").iter()
             .map(|s| SearchPath::from_cli_opt(s, error_format))
             .collect();
-        let externs = match parse_externs(&matches) {
-            Ok(ex) => ex,
-            Err(err) => {
-                diag.struct_err(&err).emit();
-                return Err(1);
-            }
-        };
+        let externs = parse_externs(&matches, &debugging_options, error_format);
         let extern_html_root_urls = match parse_extern_html_roots(&matches) {
             Ok(ex) => ex,
             Err(err) => {
@@ -617,24 +611,3 @@ fn parse_extern_html_roots(
 
     Ok(externs)
 }
-
-/// Extracts `--extern CRATE=PATH` arguments from `matches` and
-/// returns a map mapping crate names to their paths or else an
-/// error message.
-/// Also handles `--extern-private` which for the purposes of rustdoc
-/// we can treat as `--extern`
-// FIXME(eddyb) This shouldn't be duplicated with `rustc::session`.
-fn parse_externs(matches: &getopts::Matches) -> Result<Externs, String> {
-    let mut externs: BTreeMap<_, ExternEntry> = BTreeMap::new();
-    for arg in matches.opt_strs("extern").iter().chain(matches.opt_strs("extern-private").iter()) {
-        let mut parts = arg.splitn(2, '=');
-        let name = parts.next().ok_or("--extern value must not be empty".to_string())?;
-        let location = parts.next().map(|s| s.to_string());
-        let name = name.to_string();
-        // For Rustdoc purposes, we can treat all externs as public
-        externs.entry(name)
-            .or_default()
-            .locations.insert(location.clone());
-    }
-    Ok(Externs::new(externs))
-}
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index b77b1c720cf..a524801bea6 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -248,7 +248,9 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
         ..
     } = options;
 
-    let extern_names: Vec<String> = externs.iter().map(|(s,_)| s).cloned().collect();
+    let extern_names: Vec<String> = externs.iter()
+        .filter(|(_, entry)| entry.add_prelude)
+        .map(|(name, _)| name).cloned().collect();
 
     // Add the doc cfg into the doc build.
     cfgs.push("doc".to_string());
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index be3644ecf96..a4be3dee938 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -145,10 +145,6 @@ fn opts() -> Vec<RustcOptGroup> {
         stable("extern", |o| {
             o.optmulti("", "extern", "pass an --extern to rustc", "NAME[=PATH]")
         }),
-        unstable("extern-private", |o| {
-            o.optmulti("", "extern-private",
-                       "pass an --extern to rustc (compatibility only)", "NAME=PATH")
-        }),
         unstable("extern-html-root-url", |o| {
             o.optmulti("", "extern-html-root-url",
                        "base URL to use for dependencies", "NAME=URL")
diff --git a/src/test/codegen/bool-cmp.rs b/src/test/codegen/bool-cmp.rs
new file mode 100644
index 00000000000..8769a4cb5e1
--- /dev/null
+++ b/src/test/codegen/bool-cmp.rs
@@ -0,0 +1,17 @@
+// This is a test for optimal Ord trait implementation for bool.
+// See <https://github.com/rust-lang/rust/issues/66780> for more info.
+
+// compile-flags: -C opt-level=3
+
+#![crate_type = "lib"]
+
+use std::cmp::Ordering;
+
+// CHECK-LABEL: @cmp_bool
+#[no_mangle]
+pub fn cmp_bool(a: bool, b: bool) -> Ordering {
+// CHECK: zext i1
+// CHECK: zext i1
+// CHECK: sub nsw
+    a.cmp(&b)
+}
diff --git a/src/test/mir-opt/const_prop/issue-66971.rs b/src/test/mir-opt/const_prop/issue-66971.rs
new file mode 100644
index 00000000000..30c75303b3e
--- /dev/null
+++ b/src/test/mir-opt/const_prop/issue-66971.rs
@@ -0,0 +1,38 @@
+// compile-flags: -Z mir-opt-level=2
+
+// Due to a bug in propagating scalar pairs the assertion below used to fail. In the expected
+// outputs below, after ConstProp this is how _2 would look like with the bug:
+//
+//     _2 = (const Scalar(0x00) : (), const 0u8);
+//
+// Which has the wrong type.
+
+fn encode(this: ((), u8, u8)) {
+    assert!(this.2 == 0);
+}
+
+fn main() {
+    encode(((), 0, 0));
+}
+
+// END RUST SOURCE
+// START rustc.main.ConstProp.before.mir
+//  bb0: {
+//      ...
+//      _3 = ();
+//      _2 = (move _3, const 0u8, const 0u8);
+//      ...
+//      _1 = const encode(move _2) -> bb1;
+//      ...
+//  }
+// END rustc.main.ConstProp.before.mir
+// START rustc.main.ConstProp.after.mir
+//  bb0: {
+//      ...
+//      _3 = const Scalar(<ZST>) : ();
+//      _2 = (move _3, const 0u8, const 0u8);
+//      ...
+//      _1 = const encode(move _2) -> bb1;
+//      ...
+//  }
+// END rustc.main.ConstProp.after.mir
diff --git a/src/test/mir-opt/const_prop/issue-67019.rs b/src/test/mir-opt/const_prop/issue-67019.rs
new file mode 100644
index 00000000000..c6d753a1209
--- /dev/null
+++ b/src/test/mir-opt/const_prop/issue-67019.rs
@@ -0,0 +1,34 @@
+// compile-flags: -Z mir-opt-level=2
+
+// This used to ICE in const-prop
+
+fn test(this: ((u8, u8),)) {
+    assert!((this.0).0 == 1);
+}
+
+fn main() {
+    test(((1, 2),));
+}
+
+// Important bit is parameter passing so we only check that below
+// END RUST SOURCE
+// START rustc.main.ConstProp.before.mir
+//  bb0: {
+//      ...
+//      _3 = (const 1u8, const 2u8);
+//      _2 = (move _3,);
+//      ...
+//      _1 = const test(move _2) -> bb1;
+//      ...
+//  }
+// END rustc.main.ConstProp.before.mir
+// START rustc.main.ConstProp.after.mir
+//  bb0: {
+//      ...
+//      _3 = (const 1u8, const 2u8);
+//      _2 = (move _3,);
+//      ...
+//      _1 = const test(move _2) -> bb1;
+//      ...
+//  }
+// END rustc.main.ConstProp.after.mir
diff --git a/src/test/mir-opt/retain-never-const.rs b/src/test/mir-opt/retain-never-const.rs
new file mode 100644
index 00000000000..5d59b2f4842
--- /dev/null
+++ b/src/test/mir-opt/retain-never-const.rs
@@ -0,0 +1,28 @@
+// Regression test for #66975 - ensure that we don't keep unevaluated
+// `!`-typed constants until codegen.
+
+// Force generation of optimized mir for functions that do not reach codegen.
+// compile-flags: --emit mir,link
+
+#![feature(const_panic)]
+
+struct PrintName<T>(T);
+
+impl<T> PrintName<T> {
+    const VOID: ! = panic!();
+}
+
+fn no_codegen<T>() {
+    let _ = PrintName::<T>::VOID;
+}
+
+fn main() {}
+
+// END RUST SOURCE
+// START rustc.no_codegen.PreCodegen.after.mir
+// bb0: {
+//     StorageLive(_1);
+//     _1 = const PrintName::<T>::VOID;
+//     unreachable;
+// }
+// END rustc.no_codegen.PreCodegen.after.mir
diff --git a/src/test/rustdoc/issue-66159.rs b/src/test/rustdoc/issue-66159.rs
index a69ba61a283..003d079a470 100644
--- a/src/test/rustdoc/issue-66159.rs
+++ b/src/test/rustdoc/issue-66159.rs
@@ -1,6 +1,5 @@
-// aux-build:issue-66159-1.rs
+// aux-crate:priv:issue_66159_1=issue-66159-1.rs
 // compile-flags:-Z unstable-options
-// extern-private:issue_66159_1
 
 // The issue was an ICE which meant that we never actually generated the docs
 // so if we have generated the docs, we're okay.
diff --git a/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs
new file mode 100644
index 00000000000..516ca4f3f77
--- /dev/null
+++ b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs
@@ -0,0 +1,18 @@
+// Regression test for #66975
+#![warn(const_err)]
+
+struct PrintName<T>(T);
+
+impl<T> PrintName<T> {
+    const VOID: ! = { let x = 0 * std::mem::size_of::<T>(); [][x] };
+    //~^ WARN any use of this value will cause an error
+}
+
+fn f<T>() {
+    let _ = PrintName::<T>::VOID;
+    //~^ ERROR erroneous constant encountered
+}
+
+pub fn main() {
+    f::<()>();
+}
diff --git a/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr
new file mode 100644
index 00000000000..e2bd8d0cc85
--- /dev/null
+++ b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr
@@ -0,0 +1,22 @@
+warning: any use of this value will cause an error
+  --> $DIR/index-out-of-bounds-never-type.rs:7:61
+   |
+LL |     const VOID: ! = { let x = 0 * std::mem::size_of::<T>(); [][x] };
+   |     --------------------------------------------------------^^^^^---
+   |                                                             |
+   |                                                             index out of bounds: the len is 0 but the index is 0
+   |
+note: lint level defined here
+  --> $DIR/index-out-of-bounds-never-type.rs:2:9
+   |
+LL | #![warn(const_err)]
+   |         ^^^^^^^^^
+
+error: erroneous constant encountered
+  --> $DIR/index-out-of-bounds-never-type.rs:12:13
+   |
+LL |     let _ = PrintName::<T>::VOID;
+   |             ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/consts/const-eval/panic-assoc-never-type.rs b/src/test/ui/consts/const-eval/panic-assoc-never-type.rs
new file mode 100644
index 00000000000..b39d9af5546
--- /dev/null
+++ b/src/test/ui/consts/const-eval/panic-assoc-never-type.rs
@@ -0,0 +1,15 @@
+// Regression test for #66975
+#![warn(const_err)]
+#![feature(const_panic)]
+
+struct PrintName;
+
+impl PrintName {
+    const VOID: ! = panic!();
+    //~^ WARN any use of this value will cause an error
+}
+
+fn main() {
+    let _ = PrintName::VOID;
+    //~^ ERROR erroneous constant used
+}
diff --git a/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr b/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr
new file mode 100644
index 00000000000..c07c8c65a2f
--- /dev/null
+++ b/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr
@@ -0,0 +1,24 @@
+warning: any use of this value will cause an error
+  --> $DIR/panic-assoc-never-type.rs:8:21
+   |
+LL |     const VOID: ! = panic!();
+   |     ----------------^^^^^^^^-
+   |                     |
+   |                     the evaluated program panicked at 'explicit panic', $DIR/panic-assoc-never-type.rs:8:21
+   |
+note: lint level defined here
+  --> $DIR/panic-assoc-never-type.rs:2:9
+   |
+LL | #![warn(const_err)]
+   |         ^^^^^^^^^
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error[E0080]: erroneous constant used
+  --> $DIR/panic-assoc-never-type.rs:13:13
+   |
+LL |     let _ = PrintName::VOID;
+   |             ^^^^^^^^^^^^^^^ referenced constant has errors
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/panic-never-type.rs b/src/test/ui/consts/const-eval/panic-never-type.rs
new file mode 100644
index 00000000000..42eabbf5847
--- /dev/null
+++ b/src/test/ui/consts/const-eval/panic-never-type.rs
@@ -0,0 +1,11 @@
+// Regression test for #66975
+#![warn(const_err)]
+#![feature(const_panic)]
+
+const VOID: ! = panic!();
+//~^ WARN any use of this value will cause an error
+
+fn main() {
+    let _ = VOID;
+    //~^ ERROR erroneous constant used
+}
diff --git a/src/test/ui/consts/const-eval/panic-never-type.stderr b/src/test/ui/consts/const-eval/panic-never-type.stderr
new file mode 100644
index 00000000000..4fb11a61525
--- /dev/null
+++ b/src/test/ui/consts/const-eval/panic-never-type.stderr
@@ -0,0 +1,24 @@
+warning: any use of this value will cause an error
+  --> $DIR/panic-never-type.rs:5:17
+   |
+LL | const VOID: ! = panic!();
+   | ----------------^^^^^^^^-
+   |                 |
+   |                 the evaluated program panicked at 'explicit panic', $DIR/panic-never-type.rs:5:17
+   |
+note: lint level defined here
+  --> $DIR/panic-never-type.rs:2:9
+   |
+LL | #![warn(const_err)]
+   |         ^^^^^^^^^
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error[E0080]: erroneous constant used
+  --> $DIR/panic-never-type.rs:9:13
+   |
+LL |     let _ = VOID;
+   |             ^^^^ referenced constant has errors
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/extern-flag/auxiliary/somedep.rs b/src/test/ui/extern-flag/auxiliary/somedep.rs
new file mode 100644
index 00000000000..dd2f373f849
--- /dev/null
+++ b/src/test/ui/extern-flag/auxiliary/somedep.rs
@@ -0,0 +1,3 @@
+pub fn somefun() {}
+
+pub struct S;
diff --git a/src/test/ui/extern-flag/multiple-opts.rs b/src/test/ui/extern-flag/multiple-opts.rs
new file mode 100644
index 00000000000..3dc2f1d73f8
--- /dev/null
+++ b/src/test/ui/extern-flag/multiple-opts.rs
@@ -0,0 +1,20 @@
+// aux-crate:priv,noprelude:somedep=somedep.rs
+// compile-flags: -Zunstable-options
+// edition:2018
+
+// Test for multiple options to --extern. Can't test for errors from both
+// options at the same time, so this only checks that noprelude is honored.
+
+#![warn(exported_private_dependencies)]
+
+// Module to avoid adding to prelude.
+pub mod m {
+    extern crate somedep;
+    pub struct PublicType {
+        pub field: somedep::S,
+    }
+}
+
+fn main() {
+    somedep::somefun();  //~ ERROR failed to resolve
+}
diff --git a/src/test/ui/extern-flag/multiple-opts.stderr b/src/test/ui/extern-flag/multiple-opts.stderr
new file mode 100644
index 00000000000..3bf73d11cfd
--- /dev/null
+++ b/src/test/ui/extern-flag/multiple-opts.stderr
@@ -0,0 +1,9 @@
+error[E0433]: failed to resolve: use of undeclared type or module `somedep`
+  --> $DIR/multiple-opts.rs:19:5
+   |
+LL |     somedep::somefun();
+   |     ^^^^^^^ use of undeclared type or module `somedep`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/ui/extern-flag/noprelude-and-prelude.rs b/src/test/ui/extern-flag/noprelude-and-prelude.rs
new file mode 100644
index 00000000000..e6a150b9e8b
--- /dev/null
+++ b/src/test/ui/extern-flag/noprelude-and-prelude.rs
@@ -0,0 +1,10 @@
+// check-pass
+// aux-crate:noprelude:somedep=somedep.rs
+// compile-flags: -Zunstable-options --extern somedep
+// edition:2018
+
+// Having a flag with `noprelude` and one without, will add to the prelude.
+
+fn main() {
+    somedep::somefun();
+}
diff --git a/src/test/ui/extern-flag/noprelude-resolves.rs b/src/test/ui/extern-flag/noprelude-resolves.rs
new file mode 100644
index 00000000000..f69f552b69d
--- /dev/null
+++ b/src/test/ui/extern-flag/noprelude-resolves.rs
@@ -0,0 +1,11 @@
+// check-pass
+// aux-crate:noprelude:somedep=somedep.rs
+// compile-flags: -Zunstable-options
+// edition:2018
+
+// `extern crate` can be used to add to prelude.
+extern crate somedep;
+
+fn main() {
+    somedep::somefun();
+}
diff --git a/src/test/ui/extern-flag/noprelude.rs b/src/test/ui/extern-flag/noprelude.rs
new file mode 100644
index 00000000000..cdbf3409100
--- /dev/null
+++ b/src/test/ui/extern-flag/noprelude.rs
@@ -0,0 +1,7 @@
+// aux-crate:noprelude:somedep=somedep.rs
+// compile-flags: -Zunstable-options
+// edition:2018
+
+fn main() {
+    somedep::somefun();  //~ ERROR failed to resolve
+}
diff --git a/src/test/ui/extern-flag/noprelude.stderr b/src/test/ui/extern-flag/noprelude.stderr
new file mode 100644
index 00000000000..beb9200ddda
--- /dev/null
+++ b/src/test/ui/extern-flag/noprelude.stderr
@@ -0,0 +1,9 @@
+error[E0433]: failed to resolve: use of undeclared type or module `somedep`
+  --> $DIR/noprelude.rs:6:5
+   |
+LL |     somedep::somefun();
+   |     ^^^^^^^ use of undeclared type or module `somedep`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/ui/extern-flag/public-and-private.rs b/src/test/ui/extern-flag/public-and-private.rs
new file mode 100644
index 00000000000..a3a81cbf372
--- /dev/null
+++ b/src/test/ui/extern-flag/public-and-private.rs
@@ -0,0 +1,13 @@
+// aux-crate:priv:somedep=somedep.rs
+// compile-flags: -Zunstable-options --extern somedep
+// edition:2018
+
+#![deny(exported_private_dependencies)]
+
+// Having a flag with `priv` and one without, will remain private (it is sticky).
+
+pub struct PublicType {
+    pub field: somedep::S, //~ ERROR from private dependency
+}
+
+fn main() {}
diff --git a/src/test/ui/extern-flag/public-and-private.stderr b/src/test/ui/extern-flag/public-and-private.stderr
new file mode 100644
index 00000000000..72f1bb2d26f
--- /dev/null
+++ b/src/test/ui/extern-flag/public-and-private.stderr
@@ -0,0 +1,14 @@
+error: type `somedep::S` from private dependency 'somedep' in public interface
+  --> $DIR/public-and-private.rs:10:5
+   |
+LL |     pub field: somedep::S,
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+note: lint level defined here
+  --> $DIR/public-and-private.rs:5:9
+   |
+LL | #![deny(exported_private_dependencies)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/mir/issue66339.rs b/src/test/ui/mir/issue66339.rs
new file mode 100644
index 00000000000..98e178c0551
--- /dev/null
+++ b/src/test/ui/mir/issue66339.rs
@@ -0,0 +1,13 @@
+// compile-flags: -Z mir-opt-level=2
+// build-pass
+
+// This used to ICE in const-prop
+
+fn foo() {
+    let bar = |_| { };
+    let _ = bar("a");
+}
+
+fn main() {
+    foo();
+}
diff --git a/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs b/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs
index 784615354a9..feab72b3efa 100644
--- a/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs
+++ b/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs
@@ -1,11 +1,10 @@
- // aux-build:priv_dep.rs
+ // aux-crate:priv:priv_dep=priv_dep.rs
  // aux-build:pub_dep.rs
- // extern-private:priv_dep
 #![deny(exported_private_dependencies)]
 
 // This crate is a private dependency
 extern crate priv_dep;
-// This crate is a public dependenct
+// This crate is a public dependency
 extern crate pub_dep;
 
 use priv_dep::{OtherType, OtherTrait};
diff --git a/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr b/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr
index b31efdbd781..f21b11f5b32 100644
--- a/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr
+++ b/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr
@@ -1,23 +1,23 @@
 error: type `priv_dep::OtherType` from private dependency 'priv_dep' in public interface
-  --> $DIR/pub-priv1.rs:21:5
+  --> $DIR/pub-priv1.rs:20:5
    |
 LL |     pub field: OtherType,
    |     ^^^^^^^^^^^^^^^^^^^^
    |
 note: lint level defined here
-  --> $DIR/pub-priv1.rs:4:9
+  --> $DIR/pub-priv1.rs:3:9
    |
 LL | #![deny(exported_private_dependencies)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: type `priv_dep::OtherType` from private dependency 'priv_dep' in public interface
-  --> $DIR/pub-priv1.rs:28:5
+  --> $DIR/pub-priv1.rs:27:5
    |
 LL |     pub fn pub_fn(param: OtherType) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: trait `priv_dep::OtherTrait` from private dependency 'priv_dep' in public interface
-  --> $DIR/pub-priv1.rs:34:1
+  --> $DIR/pub-priv1.rs:33:1
    |
 LL | / pub trait MyPubTrait {
 LL | |     type Foo: OtherTrait;
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index dc4811e5d24..46cce6394e6 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -71,6 +71,7 @@ pub struct EarlyProps {
     pub ignore: Ignore,
     pub should_fail: bool,
     pub aux: Vec<String>,
+    pub aux_crate: Vec<(String, String)>,
     pub revisions: Vec<String>,
 }
 
@@ -80,6 +81,7 @@ impl EarlyProps {
             ignore: Ignore::Run,
             should_fail: false,
             aux: Vec::new(),
+            aux_crate: Vec::new(),
             revisions: vec![],
         };
 
@@ -157,6 +159,10 @@ impl EarlyProps {
                 props.aux.push(s);
             }
 
+            if let Some(ac) = config.parse_aux_crate(ln) {
+                props.aux_crate.push(ac);
+            }
+
             if let Some(r) = config.parse_revisions(ln) {
                 props.revisions.extend(r);
             }
@@ -311,10 +317,9 @@ pub struct TestProps {
     // directory as the test, but for backwards compatibility reasons
     // we also check the auxiliary directory)
     pub aux_builds: Vec<String>,
-    // A list of crates to pass '--extern-private name:PATH' flags for
-    // This should be a subset of 'aux_build'
-    // FIXME: Replace this with a better solution: https://github.com/rust-lang/rust/pull/54020
-    pub extern_private: Vec<String>,
+    // Similar to `aux_builds`, but a list of NAME=somelib.rs of dependencies
+    // to build and pass with the `--extern` flag.
+    pub aux_crates: Vec<(String, String)>,
     // Environment settings to use for compiling
     pub rustc_env: Vec<(String, String)>,
     // Environment variables to unset prior to compiling.
@@ -387,7 +392,7 @@ impl TestProps {
             run_flags: None,
             pp_exact: None,
             aux_builds: vec![],
-            extern_private: vec![],
+            aux_crates: vec![],
             revisions: vec![],
             rustc_env: vec![],
             unset_rustc_env: vec![],
@@ -514,8 +519,8 @@ impl TestProps {
                 self.aux_builds.push(ab);
             }
 
-            if let Some(ep) = config.parse_extern_private(ln) {
-                self.extern_private.push(ep);
+            if let Some(ac) = config.parse_aux_crate(ln) {
+                self.aux_crates.push(ac);
             }
 
             if let Some(ee) = config.parse_env(ln, "exec-env") {
@@ -713,8 +718,14 @@ impl Config {
             .map(|r| r.trim().to_string())
     }
 
-    fn parse_extern_private(&self, line: &str) -> Option<String> {
-        self.parse_name_value_directive(line, "extern-private")
+    fn parse_aux_crate(&self, line: &str) -> Option<(String, String)> {
+        self.parse_name_value_directive(line, "aux-crate").map(|r| {
+            let mut parts = r.trim().splitn(2, '=');
+            (
+                parts.next().expect("aux-crate name").to_string(),
+                parts.next().expect("aux-crate value").to_string(),
+            )
+        })
     }
 
     fn parse_compile_flags(&self, line: &str) -> Option<String> {
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 15ae67fb12c..480868440b8 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1776,93 +1776,16 @@ impl<'test> TestCx<'test> {
             create_dir_all(&aux_dir).unwrap();
         }
 
-        // Use a Vec instead of a HashMap to preserve original order
-        let mut extern_priv = self.props.extern_private.clone();
-
-        let mut add_extern_priv = |priv_dep: &str, dylib: bool| {
-            let lib_name = get_lib_name(priv_dep, dylib);
-            rustc
-                .arg("--extern-private")
-                .arg(format!("{}={}", priv_dep, aux_dir.join(lib_name).to_str().unwrap()));
-        };
-
         for rel_ab in &self.props.aux_builds {
-            let aux_testpaths = self.compute_aux_test_paths(rel_ab);
-            let aux_props =
-                self.props
-                    .from_aux_file(&aux_testpaths.file, self.revision, self.config);
-            let aux_output = TargetLocation::ThisDirectory(self.aux_output_dir_name());
-            let aux_cx = TestCx {
-                config: self.config,
-                props: &aux_props,
-                testpaths: &aux_testpaths,
-                revision: self.revision,
-            };
-            // Create the directory for the stdout/stderr files.
-            create_dir_all(aux_cx.output_base_dir()).unwrap();
-            let mut aux_rustc = aux_cx.make_compile_args(&aux_testpaths.file, aux_output);
-
-            let (dylib, crate_type) = if aux_props.no_prefer_dynamic {
-                (true, None)
-            } else if self.config.target.contains("cloudabi")
-                || self.config.target.contains("emscripten")
-                || (self.config.target.contains("musl")
-                    && !aux_props.force_host
-                    && !self.config.host.contains("musl"))
-                || self.config.target.contains("wasm32")
-                || self.config.target.contains("nvptx")
-                || self.is_vxworks_pure_static()
-            {
-                // We primarily compile all auxiliary libraries as dynamic libraries
-                // to avoid code size bloat and large binaries as much as possible
-                // for the test suite (otherwise including libstd statically in all
-                // executables takes up quite a bit of space).
-                //
-                // For targets like MUSL or Emscripten, however, there is no support for
-                // dynamic libraries so we just go back to building a normal library. Note,
-                // however, that for MUSL if the library is built with `force_host` then
-                // it's ok to be a dylib as the host should always support dylibs.
-                (false, Some("lib"))
-            } else {
-                (true, Some("dylib"))
-            };
-
-            let trimmed = rel_ab.trim_end_matches(".rs").to_string();
-
-            // Normally, every 'extern-private' has a correspodning 'aux-build'
-            // entry. If so, we remove it from our list of private crates,
-            // and add an '--extern-private' flag to rustc
-            if extern_priv.remove_item(&trimmed).is_some() {
-                add_extern_priv(&trimmed, dylib);
-            }
-
-            if let Some(crate_type) = crate_type {
-                aux_rustc.args(&["--crate-type", crate_type]);
-            }
-
-            aux_rustc.arg("-L").arg(&aux_dir);
-
-            let auxres = aux_cx.compose_and_run(
-                aux_rustc,
-                aux_cx.config.compile_lib_path.to_str().unwrap(),
-                Some(aux_dir.to_str().unwrap()),
-                None,
-            );
-            if !auxres.status.success() {
-                self.fatal_proc_rec(
-                    &format!(
-                        "auxiliary build of {:?} failed to compile: ",
-                        aux_testpaths.file.display()
-                    ),
-                    &auxres,
-                );
-            }
+            self.build_auxiliary(rel_ab, &aux_dir);
         }
 
-        // Add any '--extern-private' entries without a matching
-        // 'aux-build'
-        for private_lib in extern_priv {
-            add_extern_priv(&private_lib, true);
+        for (aux_name, aux_path) in &self.props.aux_crates {
+            let is_dylib = self.build_auxiliary(&aux_path, &aux_dir);
+            let lib_name = get_lib_name(&aux_path.trim_end_matches(".rs").replace('-', "_"),
+                is_dylib);
+            rustc.arg("--extern")
+                .arg(format!("{}={}/{}", aux_name, aux_dir.display(), lib_name));
         }
 
         self.props.unset_rustc_env.clone()
@@ -1877,6 +1800,74 @@ impl<'test> TestCx<'test> {
         )
     }
 
+    /// Builds an aux dependency.
+    ///
+    /// Returns whether or not it is a dylib.
+    fn build_auxiliary(&self, source_path: &str, aux_dir: &Path) -> bool {
+        let aux_testpaths = self.compute_aux_test_paths(source_path);
+        let aux_props =
+            self.props
+                .from_aux_file(&aux_testpaths.file, self.revision, self.config);
+        let aux_output = TargetLocation::ThisDirectory(self.aux_output_dir_name());
+        let aux_cx = TestCx {
+            config: self.config,
+            props: &aux_props,
+            testpaths: &aux_testpaths,
+            revision: self.revision,
+        };
+        // Create the directory for the stdout/stderr files.
+        create_dir_all(aux_cx.output_base_dir()).unwrap();
+        let mut aux_rustc = aux_cx.make_compile_args(&aux_testpaths.file, aux_output);
+
+        let (dylib, crate_type) = if aux_props.no_prefer_dynamic {
+            (true, None)
+        } else if self.config.target.contains("cloudabi")
+            || self.config.target.contains("emscripten")
+            || (self.config.target.contains("musl")
+                && !aux_props.force_host
+                && !self.config.host.contains("musl"))
+            || self.config.target.contains("wasm32")
+            || self.config.target.contains("nvptx")
+            || self.is_vxworks_pure_static()
+        {
+            // We primarily compile all auxiliary libraries as dynamic libraries
+            // to avoid code size bloat and large binaries as much as possible
+            // for the test suite (otherwise including libstd statically in all
+            // executables takes up quite a bit of space).
+            //
+            // For targets like MUSL or Emscripten, however, there is no support for
+            // dynamic libraries so we just go back to building a normal library. Note,
+            // however, that for MUSL if the library is built with `force_host` then
+            // it's ok to be a dylib as the host should always support dylibs.
+            (false, Some("lib"))
+        } else {
+            (true, Some("dylib"))
+        };
+
+        if let Some(crate_type) = crate_type {
+            aux_rustc.args(&["--crate-type", crate_type]);
+        }
+
+        aux_rustc.arg("-L").arg(&aux_dir);
+
+        let auxres = aux_cx.compose_and_run(
+            aux_rustc,
+            aux_cx.config.compile_lib_path.to_str().unwrap(),
+            Some(aux_dir.to_str().unwrap()),
+            None,
+        );
+        if !auxres.status.success() {
+            self.fatal_proc_rec(
+                &format!(
+                    "auxiliary build of {:?} failed to compile: ",
+                    aux_testpaths.file.display()
+                ),
+                &auxres,
+            );
+        }
+        dylib
+    }
+
     fn compose_and_run(
         &self,
         mut command: Command,