From 4ca769ad091ef0018f5a20effaf4b4f428a034d7 Mon Sep 17 00:00:00 2001 From: Krishna Sai Veera Reddy Date: Fri, 29 Nov 2019 15:22:44 -0700 Subject: [PATCH 1/9] Optimize Ord trait implementation for bool Casting the booleans to `i8`s and converting their difference into `Ordering` generates better assembly than casting them to `u8`s and comparing them. --- src/libcore/cmp.rs | 11 ++++++++++- src/libcore/tests/cmp.rs | 8 ++++++++ src/test/codegen/bool-cmp.rs | 17 +++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 src/test/codegen/bool-cmp.rs diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index eea3dc39d345e..e72b6117ba862 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -1006,6 +1006,7 @@ pub fn max_by_key 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 { @@ -1126,7 +1127,15 @@ 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 for more info. + match (*self as i8) - (*other as i8) { + -1 => Less, + 0 => Equal, + 1 => Greater, + _ => unsafe { unreachable_unchecked() }, + } } } diff --git a/src/libcore/tests/cmp.rs b/src/libcore/tests/cmp.rs index 5e6778e222a29..56a2f4acf6eaa 100644 --- a/src/libcore/tests/cmp.rs +++ b/src/libcore/tests/cmp.rs @@ -9,6 +9,14 @@ fn test_int_totalord() { assert_eq!(12.cmp(&-5), Greater); } +#[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); diff --git a/src/test/codegen/bool-cmp.rs b/src/test/codegen/bool-cmp.rs new file mode 100644 index 0000000000000..8769a4cb5e189 --- /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 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) +} From a30ee8e7636d2cf26eba89a8402cdfefebf9845e Mon Sep 17 00:00:00 2001 From: Krishna Sai Veera Reddy Date: Mon, 2 Dec 2019 08:45:35 -0700 Subject: [PATCH 2/9] Document usage of unsafe block --- src/libcore/cmp.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index e72b6117ba862..e16a428feb645 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -1134,6 +1134,7 @@ mod impls { -1 => Less, 0 => Equal, 1 => Greater, + // SAFETY: Unreachable code _ => unsafe { unreachable_unchecked() }, } } From 2404a067eedd83ab69bb0e07fdc8145825741722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Sinan=20A=C4=9Facan?= Date: Thu, 5 Dec 2019 10:40:24 +0300 Subject: [PATCH 3/9] const-prop: Restrict scalar pair propagation We now only propagate a scalar pair if the Rvalue is a tuple with two scalars. This for example avoids propagating a (u8, u8) value when Rvalue has type `((), u8, u8)` (see the regression test). While this is a correct thing to do, implementation is tricky and will be done later. Fixes #66971 Fixes #66339 Fixes #67019 --- src/librustc_mir/transform/const_prop.rs | 48 +++++++++++++++++----- src/librustc_target/abi/mod.rs | 8 ++++ src/test/mir-opt/const_prop/issue-66971.rs | 38 +++++++++++++++++ src/test/mir-opt/const_prop/issue-67019.rs | 34 +++++++++++++++ src/test/ui/mir/issue66339.rs | 13 ++++++ 5 files changed, 130 insertions(+), 11 deletions(-) create mode 100644 src/test/mir-opt/const_prop/issue-66971.rs create mode 100644 src/test/mir-opt/const_prop/issue-67019.rs create mode 100644 src/test/ui/mir/issue66339.rs diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 95de635d634e4..a147ad3bb1e22 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_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index ac781819cc35e..b0bc052929768 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/test/mir-opt/const_prop/issue-66971.rs b/src/test/mir-opt/const_prop/issue-66971.rs new file mode 100644 index 0000000000000..30c75303b3e53 --- /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() : (); +// _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 0000000000000..c6d753a1209cd --- /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/ui/mir/issue66339.rs b/src/test/ui/mir/issue66339.rs new file mode 100644 index 0000000000000..98e178c055146 --- /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(); +} From a983e0590a43ed8b0f60417828efd4e79b51f494 Mon Sep 17 00:00:00 2001 From: Matthew Kraai Date: Mon, 9 Dec 2019 06:49:37 -0800 Subject: [PATCH 4/9] Remove `checked_add` in `Layout::repeat` --- src/libcore/alloc.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 20248f7f6c13e..3ebdb916f9935 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: () })?; From 590dd7dfef3e835756edb5f920bf31cd19eef4d0 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 5 Dec 2019 14:43:53 -0800 Subject: [PATCH 5/9] Add options to --extern flag. --- src/librustc_interface/tests.rs | 23 +-- src/librustc_metadata/creader.rs | 15 +- src/librustc_metadata/locator.rs | 5 +- src/librustc_resolve/lib.rs | 6 +- src/librustc_session/config.rs | 169 ++++++++++++++---- src/librustdoc/config.rs | 33 +--- src/librustdoc/core.rs | 4 +- src/librustdoc/lib.rs | 4 - .../extern-flag-noprelude/Makefile | 11 ++ .../extern-flag-noprelude/dep.rs | 3 + .../extern-flag-noprelude/foo.rs | 3 + src/test/ui/extern-flag/multiple-opts.rs | 20 +++ src/test/ui/extern-flag/multiple-opts.stderr | 9 + .../ui/extern-flag/noprelude-and-prelude.rs | 10 ++ src/test/ui/extern-flag/public-and-private.rs | 13 ++ .../ui/extern-flag/public-and-private.stderr | 14 ++ src/tools/compiletest/src/header.rs | 2 +- src/tools/compiletest/src/runtest.rs | 10 +- 18 files changed, 254 insertions(+), 100 deletions(-) create mode 100644 src/test/run-make-fulldeps/extern-flag-noprelude/Makefile create mode 100644 src/test/run-make-fulldeps/extern-flag-noprelude/dep.rs create mode 100644 src/test/run-make-fulldeps/extern-flag-noprelude/foo.rs create mode 100644 src/test/ui/extern-flag/multiple-opts.rs create mode 100644 src/test/ui/extern-flag/multiple-opts.stderr create mode 100644 src/test/ui/extern-flag/noprelude-and-prelude.rs create mode 100644 src/test/ui/extern-flag/public-and-private.rs create mode 100644 src/test/ui/extern-flag/public-and-private.stderr diff --git a/src/librustc_interface/tests.rs b/src/librustc_interface/tests.rs index 4c630b56cb4ce..d4b5e833dfb23 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(locations: I) -> ExternEntry where S: Into, - I: IntoIterator>, + I: IntoIterator, { - 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 dbf2dcf1c0aea..71871373e35e9 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 c6fb80eca055a..8a1eeea02512e 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_resolve/lib.rs b/src/librustc_resolve/lib.rs index be36e02f5b5b1..2aa79d7b0da50 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1126,8 +1126,10 @@ impl<'a> Resolver<'a> { definitions.create_root_def(crate_name, session.local_crate_disambiguator()); let mut extern_prelude: FxHashMap> = - 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 58113bb8cd6cb..7f3bab8f23299 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); -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct ExternEntry { - pub locations: BTreeSet>, - 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), } 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> { + 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 { "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, bool)>>`, - // and later convert it into a `BTreeSet<(Option, 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 = 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/librustdoc/config.rs b/src/librustdoc/config.rs index cdb1a1f6997c9..0db3d28bf0e37 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 { - 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 b77b1c720cfdf..a524801bea6bf 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 = externs.iter().map(|(s,_)| s).cloned().collect(); + let extern_names: Vec = 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 be3644ecf96a7..a4be3dee938ed 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -145,10 +145,6 @@ fn opts() -> Vec { 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/run-make-fulldeps/extern-flag-noprelude/Makefile b/src/test/run-make-fulldeps/extern-flag-noprelude/Makefile new file mode 100644 index 0000000000000..18f9d8bab6004 --- /dev/null +++ b/src/test/run-make-fulldeps/extern-flag-noprelude/Makefile @@ -0,0 +1,11 @@ +-include ../tools.mk + +# Test --extern noprelude + +all: + $(RUSTC) dep.rs --crate-name=dep --crate-type=rlib + $(RUSTC) foo.rs --edition=2018 -Zunstable-options \ + --extern noprelude:dep=$(TMPDIR)/libdep.rlib 2>&1 | \ + $(CGREP) -e 'failed to resolve.*`dep`' + $(RUSTC) foo.rs --edition=2018 -Zunstable-options \ + --extern dep=$(TMPDIR)/libdep.rlib diff --git a/src/test/run-make-fulldeps/extern-flag-noprelude/dep.rs b/src/test/run-make-fulldeps/extern-flag-noprelude/dep.rs new file mode 100644 index 0000000000000..dd2f373f849c6 --- /dev/null +++ b/src/test/run-make-fulldeps/extern-flag-noprelude/dep.rs @@ -0,0 +1,3 @@ +pub fn somefun() {} + +pub struct S; diff --git a/src/test/run-make-fulldeps/extern-flag-noprelude/foo.rs b/src/test/run-make-fulldeps/extern-flag-noprelude/foo.rs new file mode 100644 index 0000000000000..9bb1b78409f86 --- /dev/null +++ b/src/test/run-make-fulldeps/extern-flag-noprelude/foo.rs @@ -0,0 +1,3 @@ +fn main() { + dep::somefun(); +} 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 0000000000000..3dc2f1d73f8e4 --- /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 0000000000000..3bf73d11cfd22 --- /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 0000000000000..e6a150b9e8b9e --- /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/public-and-private.rs b/src/test/ui/extern-flag/public-and-private.rs new file mode 100644 index 0000000000000..a3a81cbf37223 --- /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 0000000000000..72f1bb2d26f1a --- /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/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index dc4811e5d24ce..ca30e782c5056 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -311,7 +311,7 @@ pub struct TestProps { // directory as the test, but for backwards compatibility reasons // we also check the auxiliary directory) pub aux_builds: Vec, - // A list of crates to pass '--extern-private name:PATH' flags for + // A list of crates to pass '--extern priv: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, diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 15ae67fb12c51..ca68fe3e39b96 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1782,8 +1782,8 @@ impl<'test> TestCx<'test> { 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())); + .arg("--extern") + .arg(format!("priv:{}={}", priv_dep, aux_dir.join(lib_name).to_str().unwrap())); }; for rel_ab in &self.props.aux_builds { @@ -1829,9 +1829,9 @@ impl<'test> TestCx<'test> { let trimmed = rel_ab.trim_end_matches(".rs").to_string(); - // Normally, every 'extern-private' has a correspodning 'aux-build' + // Normally, every 'extern-private' has a corresponding 'aux-build' // entry. If so, we remove it from our list of private crates, - // and add an '--extern-private' flag to rustc + // and add an '--extern priv:NAME=PATH' flag to rustc if extern_priv.remove_item(&trimmed).is_some() { add_extern_priv(&trimmed, dylib); } @@ -1859,7 +1859,7 @@ impl<'test> TestCx<'test> { } } - // Add any '--extern-private' entries without a matching + // Add any '--extern' private entries without a matching // 'aux-build' for private_lib in extern_priv { add_extern_priv(&private_lib, true); From 60d4e20ff07ac4546f47f09094c7c04b577f0966 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 5 Dec 2019 16:26:21 -0800 Subject: [PATCH 6/9] compiletest: add aux-crate directive --- .../extern-flag-noprelude/Makefile | 11 -- .../extern-flag-noprelude/foo.rs | 3 - src/test/rustdoc/issue-66159.rs | 3 +- .../extern-flag/auxiliary/somedep.rs} | 0 src/test/ui/extern-flag/noprelude-resolves.rs | 11 ++ src/test/ui/extern-flag/noprelude.rs | 7 + src/test/ui/extern-flag/noprelude.stderr | 9 + src/test/ui/privacy/pub-priv-dep/pub-priv1.rs | 5 +- .../ui/privacy/pub-priv-dep/pub-priv1.stderr | 8 +- src/tools/compiletest/src/header.rs | 29 +++- src/tools/compiletest/src/runtest.rs | 159 +++++++++--------- 11 files changed, 129 insertions(+), 116 deletions(-) delete mode 100644 src/test/run-make-fulldeps/extern-flag-noprelude/Makefile delete mode 100644 src/test/run-make-fulldeps/extern-flag-noprelude/foo.rs rename src/test/{run-make-fulldeps/extern-flag-noprelude/dep.rs => ui/extern-flag/auxiliary/somedep.rs} (100%) create mode 100644 src/test/ui/extern-flag/noprelude-resolves.rs create mode 100644 src/test/ui/extern-flag/noprelude.rs create mode 100644 src/test/ui/extern-flag/noprelude.stderr diff --git a/src/test/run-make-fulldeps/extern-flag-noprelude/Makefile b/src/test/run-make-fulldeps/extern-flag-noprelude/Makefile deleted file mode 100644 index 18f9d8bab6004..0000000000000 --- a/src/test/run-make-fulldeps/extern-flag-noprelude/Makefile +++ /dev/null @@ -1,11 +0,0 @@ --include ../tools.mk - -# Test --extern noprelude - -all: - $(RUSTC) dep.rs --crate-name=dep --crate-type=rlib - $(RUSTC) foo.rs --edition=2018 -Zunstable-options \ - --extern noprelude:dep=$(TMPDIR)/libdep.rlib 2>&1 | \ - $(CGREP) -e 'failed to resolve.*`dep`' - $(RUSTC) foo.rs --edition=2018 -Zunstable-options \ - --extern dep=$(TMPDIR)/libdep.rlib diff --git a/src/test/run-make-fulldeps/extern-flag-noprelude/foo.rs b/src/test/run-make-fulldeps/extern-flag-noprelude/foo.rs deleted file mode 100644 index 9bb1b78409f86..0000000000000 --- a/src/test/run-make-fulldeps/extern-flag-noprelude/foo.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - dep::somefun(); -} diff --git a/src/test/rustdoc/issue-66159.rs b/src/test/rustdoc/issue-66159.rs index a69ba61a283d0..003d079a470c0 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/run-make-fulldeps/extern-flag-noprelude/dep.rs b/src/test/ui/extern-flag/auxiliary/somedep.rs similarity index 100% rename from src/test/run-make-fulldeps/extern-flag-noprelude/dep.rs rename to src/test/ui/extern-flag/auxiliary/somedep.rs 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 0000000000000..f69f552b69d8a --- /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 0000000000000..cdbf34091007e --- /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 0000000000000..beb9200dddabc --- /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/privacy/pub-priv-dep/pub-priv1.rs b/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs index 784615354a95c..feab72b3efa42 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 b31efdbd781dc..f21b11f5b32f8 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 ca30e782c5056..46cce6394e617 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, + pub aux_crate: Vec<(String, String)>, pub revisions: Vec, } @@ -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, - // A list of crates to pass '--extern priv: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, + // 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 { - 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 { diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index ca68fe3e39b96..480868440b8dc 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") - .arg(format!("priv:{}={}", 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 corresponding 'aux-build' - // entry. If so, we remove it from our list of private crates, - // and add an '--extern priv:NAME=PATH' 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, From d2ed209699b169808293223f6a3b83e755fdf708 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 8 Dec 2019 21:50:23 +0000 Subject: [PATCH 7/9] Ensure that unevaluated constants of type `!` are present in the MIR --- src/librustc_mir/build/expr/into.rs | 9 +++++- src/test/mir-opt/retain-never-const.rs | 28 +++++++++++++++++++ .../index-out-of-bounds-never-type.rs | 18 ++++++++++++ .../index-out-of-bounds-never-type.stderr | 22 +++++++++++++++ .../const-eval/panic-assoc-never-type.rs | 15 ++++++++++ .../const-eval/panic-assoc-never-type.stderr | 24 ++++++++++++++++ .../ui/consts/const-eval/panic-never-type.rs | 11 ++++++++ .../consts/const-eval/panic-never-type.stderr | 24 ++++++++++++++++ 8 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 src/test/mir-opt/retain-never-const.rs create mode 100644 src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs create mode 100644 src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr create mode 100644 src/test/ui/consts/const-eval/panic-assoc-never-type.rs create mode 100644 src/test/ui/consts/const-eval/panic-assoc-never-type.stderr create mode 100644 src/test/ui/consts/const-eval/panic-never-type.rs create mode 100644 src/test/ui/consts/const-eval/panic-never-type.stderr diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index f5dc09ccebc1e..07a44b190b20a 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/test/mir-opt/retain-never-const.rs b/src/test/mir-opt/retain-never-const.rs new file mode 100644 index 0000000000000..5d59b2f48429d --- /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); + +impl PrintName { + const VOID: ! = panic!(); +} + +fn no_codegen() { + let _ = PrintName::::VOID; +} + +fn main() {} + +// END RUST SOURCE +// START rustc.no_codegen.PreCodegen.after.mir +// bb0: { +// StorageLive(_1); +// _1 = const PrintName::::VOID; +// unreachable; +// } +// END rustc.no_codegen.PreCodegen.after.mir 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 0000000000000..516ca4f3f77e0 --- /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); + +impl PrintName { + const VOID: ! = { let x = 0 * std::mem::size_of::(); [][x] }; + //~^ WARN any use of this value will cause an error +} + +fn f() { + let _ = PrintName::::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 0000000000000..e2bd8d0cc85ea --- /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::(); [][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::::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 0000000000000..b39d9af5546f8 --- /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 0000000000000..c07c8c65a2f20 --- /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 0000000000000..42eabbf58470f --- /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 0000000000000..4fb11a61525f4 --- /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`. From 472e7548d866920e5f798d88e023ea0c8efa8b19 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Wed, 11 Dec 2019 05:26:40 +0900 Subject: [PATCH 8/9] Make it executable --- src/ci/publish_toolstate.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 src/ci/publish_toolstate.sh diff --git a/src/ci/publish_toolstate.sh b/src/ci/publish_toolstate.sh old mode 100644 new mode 100755 From 1f07aa582a41e6fc253139909d3bf9bfd04a9d6d Mon Sep 17 00:00:00 2001 From: Krishna Sai Veera Reddy Date: Tue, 10 Dec 2019 14:30:06 -0700 Subject: [PATCH 9/9] Add better documentation for unsafe block --- src/libcore/cmp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index e16a428feb645..87a407c5e9f7b 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -1134,7 +1134,7 @@ mod impls { -1 => Less, 0 => Equal, 1 => Greater, - // SAFETY: Unreachable code + // SAFETY: bool as i8 returns 0 or 1, so the difference can't be anything else _ => unsafe { unreachable_unchecked() }, } }