From 4a90ab6910a92f41ca9975981bbdcae027a6257c Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Wed, 17 Mar 2021 15:19:54 -0700 Subject: [PATCH 01/13] Add -Zallow-features to match rustc's -Z --- src/bin/cargo/cli.rs | 1 + src/cargo/core/features.rs | 59 +++++++++++++++++++++++++++++-- src/doc/src/reference/unstable.md | 21 +++++++++++ tests/testsuite/cargo_features.rs | 58 ++++++++++++++++++++++++++++++ 4 files changed, 136 insertions(+), 3 deletions(-) diff --git a/src/bin/cargo/cli.rs b/src/bin/cargo/cli.rs index 9c609ca5e77..55d7bd9bfdc 100644 --- a/src/bin/cargo/cli.rs +++ b/src/bin/cargo/cli.rs @@ -35,6 +35,7 @@ pub fn main(config: &mut Config) -> CliResult { " Available unstable (nightly-only) flags: + -Z allow-features -- Allow *only* the listed unstable features -Z avoid-dev-deps -- Avoid installing dev-dependencies if possible -Z extra-link-arg -- Allow `cargo:rustc-link-arg` in build scripts -Z minimal-versions -- Install minimal dependency versions instead of maximum diff --git a/src/cargo/core/features.rs b/src/cargo/core/features.rs index cdebf99a6a7..f78527723fd 100644 --- a/src/cargo/core/features.rs +++ b/src/cargo/core/features.rs @@ -92,6 +92,7 @@ //! of that page. Update the rest of the documentation to add the new //! feature. +use std::collections::HashSet; use std::env; use std::fmt; use std::str::FromStr; @@ -415,13 +416,18 @@ impl Features { let mut ret = Features::default(); ret.nightly_features_allowed = config.nightly_features_allowed; for feature in features { - ret.add(feature, warnings)?; + ret.add(feature, config, warnings)?; ret.activated.push(feature.to_string()); } Ok(ret) } - fn add(&mut self, feature_name: &str, warnings: &mut Vec) -> CargoResult<()> { + fn add( + &mut self, + feature_name: &str, + config: &Config, + warnings: &mut Vec, + ) -> CargoResult<()> { let nightly_features_allowed = self.nightly_features_allowed; let (slot, feature) = match self.status(feature_name) { Some(p) => p, @@ -469,6 +475,24 @@ impl Features { SEE_CHANNELS, see_docs() ), + Status::Unstable + if !config + .cli_unstable() + .allow_features + .as_ref() + .map(|f| f.contains(feature_name)) + .unwrap_or(true) => + { + bail!( + "the feature `{}` is not in the list of allowed features: {:?}", + feature_name, + config + .cli_unstable() + .allow_features + .as_ref() + .expect("!unwrap_or(true) == false") + ) + } Status::Unstable => {} Status::Removed => bail!( "the cargo feature `{}` has been removed\n\ @@ -530,6 +554,8 @@ impl Features { #[serde(default, rename_all = "kebab-case")] pub struct CliUnstable { pub print_im_a_teapot: bool, + pub allow_features: Option>, + pub unstable_options: bool, pub no_index_update: bool, pub avoid_dev_deps: bool, @@ -627,7 +653,32 @@ impl CliUnstable { } let mut warnings = Vec::new(); for flag in flags { - self.add(flag, &mut warnings)?; + if flag.starts_with("allow-features=") { + self.add(flag, &mut warnings)?; + } + } + if let Some(allowed) = self.allow_features.take() { + for flag in flags { + let k = flag + .splitn(2, '=') + .next() + .expect("split always yields >=1 item"); + if k == "allow-features" { + } else if allowed.contains(k) { + self.add(flag, &mut warnings)?; + } else { + bail!( + "the feature `{}` is not in the list of allowed features: {:?}", + k, + allowed + ); + } + } + self.allow_features = Some(allowed); + } else { + for flag in flags { + self.add(flag, &mut warnings)?; + } } Ok(warnings) } @@ -655,6 +706,7 @@ impl CliUnstable { fn parse_features(value: Option<&str>) -> Vec { match value { None => Vec::new(), + Some("") => Vec::new(), Some(v) => v.split(',').map(|s| s.to_string()).collect(), } } @@ -699,6 +751,7 @@ impl CliUnstable { match k { "print-im-a-teapot" => self.print_im_a_teapot = parse_bool(k, v)?, + "allow-features" => self.allow_features = Some(parse_features(v).into_iter().collect()), "unstable-options" => self.unstable_options = parse_empty(k, v)?, "no-index-update" => self.no_index_update = parse_empty(k, v)?, "avoid-dev-deps" => self.avoid_dev_deps = parse_empty(k, v)?, diff --git a/src/doc/src/reference/unstable.md b/src/doc/src/reference/unstable.md index b1ef069074c..e6b09f51c14 100644 --- a/src/doc/src/reference/unstable.md +++ b/src/doc/src/reference/unstable.md @@ -58,6 +58,27 @@ Each new feature described below should explain how to use it. [nightly channel]: ../../book/appendix-07-nightly-rust.html [stabilized]: https://doc.crates.io/contrib/process/unstable.html#stabilization +### allow-features + +This permanently-unstable flag makes it so that only a listed set of +unstable features can be used. Specifically, if you pass +`-Zallow-features=foo,bar`, you'll continue to be able to pass `-Zfoo` +and `-Zbar` to `cargo`, but you will be unable to pass `-Zbaz`. You can +pass an empty string (`-Zallow-features=`) to disallow all unstable +features. + +`-Zallow-features` also restricts which unstable features can be passed +to the `cargo-features` entry in `Cargo.toml`. If, for example, you want +to allow + +```toml +cargo-features = ["test-dummy-unstable"] +``` + +where `test-dummy-unstable` is unstable, that features would also be +disallowed by `-Zallow-features=`, and allowed with +`-Zallow-features=test-dummy-unstable`. + ### extra-link-arg * Original Pull Request: [#7811](https://github.com/rust-lang/cargo/pull/7811) diff --git a/tests/testsuite/cargo_features.rs b/tests/testsuite/cargo_features.rs index 806fc4195c9..f95eab0ddf9 100644 --- a/tests/testsuite/cargo_features.rs +++ b/tests/testsuite/cargo_features.rs @@ -113,6 +113,64 @@ release and is no longer necessary to be listed in the manifest .run(); } +#[cargo_test] +fn allow_features() { + let p = project() + .file( + "Cargo.toml", + r#" + cargo-features = ["test-dummy-unstable"] + + [package] + name = "a" + version = "0.0.1" + authors = [] + im-a-teapot = true + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("-Zallow-features=test-dummy-unstable build") + .masquerade_as_nightly_cargo() + .with_stderr( + "\ +[COMPILING] a [..] +[FINISHED] [..] +", + ) + .run(); + + p.cargo("-Zallow-features=test-dummy-unstable,print-im-a-teapot -Zprint-im-a-teapot build") + .masquerade_as_nightly_cargo() + .with_stdout("im-a-teapot = true") + .with_stderr("[FINISHED] [..]") + .run(); + + p.cargo("-Zallow-features=test-dummy-unstable -Zprint-im-a-teapot build") + .masquerade_as_nightly_cargo() + .with_status(101) + .with_stderr( + "\ +error: the feature `print-im-a-teapot` is not in the list of allowed features: {\"test-dummy-unstable\"} +", + ) + .run(); + + p.cargo("-Zallow-features= build") + .masquerade_as_nightly_cargo() + .with_status(101) + .with_stderr( + "\ +error: failed to parse manifest at `[..]` + +Caused by: + the feature `test-dummy-unstable` is not in the list of allowed features: {} +", + ) + .run(); +} + #[cargo_test] fn nightly_feature_requires_nightly() { let p = project() From caca4d43a0ddee6e891d956eccecbd9708ea0050 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Wed, 24 Mar 2021 09:42:36 -0700 Subject: [PATCH 02/13] Test that allowed-features in config works --- tests/testsuite/cargo_features.rs | 76 +++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/tests/testsuite/cargo_features.rs b/tests/testsuite/cargo_features.rs index f95eab0ddf9..4a0cefe5835 100644 --- a/tests/testsuite/cargo_features.rs +++ b/tests/testsuite/cargo_features.rs @@ -171,6 +171,82 @@ Caused by: .run(); } +#[cargo_test] +fn allow_features_in_cfg() { + let p = project() + .file( + "Cargo.toml", + r#" + cargo-features = ["test-dummy-unstable"] + + [package] + name = "a" + version = "0.0.1" + authors = [] + im-a-teapot = true + "#, + ) + .file( + ".cargo/config.toml", + r#" + [unstable] + allow-features = ["test-dummy-unstable", "print-im-a-teapot"] + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("build") + .masquerade_as_nightly_cargo() + .with_stderr( + "\ +[COMPILING] a [..] +[FINISHED] [..] +", + ) + .run(); + + p.cargo("-Zprint-im-a-teapot build") + .masquerade_as_nightly_cargo() + .with_stdout("im-a-teapot = true") + .with_stderr("[FINISHED] [..]") + .run(); + + p.cargo("-Zunstable-options build") + .masquerade_as_nightly_cargo() + .with_status(101) + .with_stderr( + "\ +error: the feature `unstable-options` is not in the list of allowed features: {[..]} +", + ) + .run(); + + // -Zallow-features overrides .cargo/config + p.cargo("-Zallow-features=test-dummy-unstable -Zprint-im-a-teapot build") + .masquerade_as_nightly_cargo() + .with_status(101) + .with_stderr( + "\ +error: the feature `print-im-a-teapot` is not in the list of allowed features: {\"test-dummy-unstable\"} +", + ) + .run(); + + p.cargo("-Zallow-features= build") + .masquerade_as_nightly_cargo() + .with_status(101) + .with_stderr( + "\ +error: failed to parse manifest at `[..]` + +Caused by: + the feature `test-dummy-unstable` is not in the list of allowed features: {} +", + ) + .run(); +} + #[cargo_test] fn nightly_feature_requires_nightly() { let p = project() From 85f7c800f8dfbf78216b1c1fdc1f05c6b00661f0 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Wed, 24 Mar 2021 10:14:53 -0700 Subject: [PATCH 03/13] Forward -Zallow-features to rustc --- src/cargo/core/compiler/compilation.rs | 13 ++++++ src/doc/src/reference/unstable.md | 5 ++ tests/testsuite/cargo_features.rs | 64 ++++++++++++++++++++++++++ 3 files changed, 82 insertions(+) diff --git a/src/cargo/core/compiler/compilation.rs b/src/cargo/core/compiler/compilation.rs index dbde49eb2c3..d8361a2d24f 100644 --- a/src/cargo/core/compiler/compilation.rs +++ b/src/cargo/core/compiler/compilation.rs @@ -338,6 +338,19 @@ impl<'cfg> Compilation<'cfg> { .env("CARGO_PKG_AUTHORS", &pkg.authors().join(":")) .cwd(pkg.root()); + if is_rustc_tool { + if let Some(allow) = &self.config.cli_unstable().allow_features { + let mut arg = String::from("-Zallow-features="); + for (i, a) in allow.iter().enumerate() { + arg.push_str(a); + if i != allow.len() - 1 { + arg.push(','); + } + } + cmd.arg(&arg); + } + } + if self.config.cli_unstable().configurable_env { // Apply any environment variables from the config for (key, value) in self.config.env_config()?.iter() { diff --git a/src/doc/src/reference/unstable.md b/src/doc/src/reference/unstable.md index e6b09f51c14..48fa88aacbf 100644 --- a/src/doc/src/reference/unstable.md +++ b/src/doc/src/reference/unstable.md @@ -79,6 +79,11 @@ where `test-dummy-unstable` is unstable, that features would also be disallowed by `-Zallow-features=`, and allowed with `-Zallow-features=test-dummy-unstable`. +The list of features passed to cargo's `-Zallow-features` is also passed +to any Rust tools that cargo ends up calling (like `rustc` or +`rustdoc`). Thus, if you run `cargo -Zallow-features=`, no unstable +Cargo _or_ Rust features can be used. + ### extra-link-arg * Original Pull Request: [#7811](https://github.com/rust-lang/cargo/pull/7811) diff --git a/tests/testsuite/cargo_features.rs b/tests/testsuite/cargo_features.rs index 4a0cefe5835..7d9eec8fd15 100644 --- a/tests/testsuite/cargo_features.rs +++ b/tests/testsuite/cargo_features.rs @@ -131,8 +131,11 @@ fn allow_features() { .file("src/lib.rs", "") .build(); + // NOTE: We need to use RUSTC_BOOTSTRAP here since we also need nightly rustc + p.cargo("-Zallow-features=test-dummy-unstable build") .masquerade_as_nightly_cargo() + .env("RUSTC_BOOTSTRAP", "1") .with_stderr( "\ [COMPILING] a [..] @@ -143,12 +146,14 @@ fn allow_features() { p.cargo("-Zallow-features=test-dummy-unstable,print-im-a-teapot -Zprint-im-a-teapot build") .masquerade_as_nightly_cargo() + .env("RUSTC_BOOTSTRAP", "1") .with_stdout("im-a-teapot = true") .with_stderr("[FINISHED] [..]") .run(); p.cargo("-Zallow-features=test-dummy-unstable -Zprint-im-a-teapot build") .masquerade_as_nightly_cargo() + .env("RUSTC_BOOTSTRAP", "1") .with_status(101) .with_stderr( "\ @@ -159,6 +164,7 @@ error: the feature `print-im-a-teapot` is not in the list of allowed features: { p.cargo("-Zallow-features= build") .masquerade_as_nightly_cargo() + .env("RUSTC_BOOTSTRAP", "1") .with_status(101) .with_stderr( "\ @@ -171,6 +177,57 @@ Caused by: .run(); } +#[cargo_test] +fn allow_features_to_rustc() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "a" + version = "0.0.1" + authors = [] + "#, + ) + .file( + "src/lib.rs", + r#" + #![feature(test_2018_feature)] + "#, + ) + .build(); + + // NOTE: We need to use RUSTC_BOOTSTRAP here since we also need nightly rustc + + p.cargo("-Zallow-features= build") + .masquerade_as_nightly_cargo() + .env("RUSTC_BOOTSTRAP", "1") + .with_status(101) + .with_stderr_contains( + "\ +[COMPILING] a [..] +error[E0725]: the feature `test_2018_feature` is not in the list of allowed features +", + ) + .with_stderr_contains( + "\ +error: could not compile `a` +", + ) + .run(); + + p.cargo("-Zallow-features=test_2018_feature build") + .masquerade_as_nightly_cargo() + .env("RUSTC_BOOTSTRAP", "1") + .with_stderr( + "\ +[COMPILING] a [..] +[FINISHED] [..] +", + ) + .run(); +} + #[cargo_test] fn allow_features_in_cfg() { let p = project() @@ -196,8 +253,11 @@ fn allow_features_in_cfg() { .file("src/lib.rs", "") .build(); + // NOTE: We need to use RUSTC_BOOTSTRAP here since we also need nightly rustc + p.cargo("build") .masquerade_as_nightly_cargo() + .env("RUSTC_BOOTSTRAP", "1") .with_stderr( "\ [COMPILING] a [..] @@ -208,12 +268,14 @@ fn allow_features_in_cfg() { p.cargo("-Zprint-im-a-teapot build") .masquerade_as_nightly_cargo() + .env("RUSTC_BOOTSTRAP", "1") .with_stdout("im-a-teapot = true") .with_stderr("[FINISHED] [..]") .run(); p.cargo("-Zunstable-options build") .masquerade_as_nightly_cargo() + .env("RUSTC_BOOTSTRAP", "1") .with_status(101) .with_stderr( "\ @@ -225,6 +287,7 @@ error: the feature `unstable-options` is not in the list of allowed features: {[ // -Zallow-features overrides .cargo/config p.cargo("-Zallow-features=test-dummy-unstable -Zprint-im-a-teapot build") .masquerade_as_nightly_cargo() + .env("RUSTC_BOOTSTRAP", "1") .with_status(101) .with_stderr( "\ @@ -235,6 +298,7 @@ error: the feature `print-im-a-teapot` is not in the list of allowed features: { p.cargo("-Zallow-features= build") .masquerade_as_nightly_cargo() + .env("RUSTC_BOOTSTRAP", "1") .with_status(101) .with_stderr( "\ From 937d1b6fdf814bbed2cb7575fe53cf01c73f00a9 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Wed, 31 Mar 2021 12:33:24 -0700 Subject: [PATCH 04/13] util: Add iterator join method --- src/cargo/util/mod.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/cargo/util/mod.rs b/src/cargo/util/mod.rs index 42b243bf917..4efd9b7193c 100644 --- a/src/cargo/util/mod.rs +++ b/src/cargo/util/mod.rs @@ -1,3 +1,4 @@ +use std::fmt; use std::time::Duration; pub use self::canonical_url::CanonicalUrl; @@ -75,6 +76,32 @@ pub fn elapsed(duration: Duration) -> String { } } +pub fn iter_join_onto(mut w: W, iter: I, delim: &str) -> fmt::Result +where + W: fmt::Write, + I: IntoIterator, + T: std::fmt::Display, +{ + let mut it = iter.into_iter().peekable(); + while let Some(n) = it.next() { + write!(w, "{}", n)?; + if it.peek().is_some() { + write!(w, "{}", delim)?; + } + } + Ok(()) +} + +pub fn iter_join(iter: I, delim: &str) -> String +where + I: IntoIterator, + T: std::fmt::Display, +{ + let mut s = String::new(); + let _ = iter_join_onto(&mut s, iter, delim); + s +} + /// Whether or not this running in a Continuous Integration environment. pub fn is_ci() -> bool { std::env::var("CI").is_ok() || std::env::var("TF_BUILD").is_ok() From a0549c09bf31aaef39c4a92a429e238d04c556bc Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Wed, 31 Mar 2021 12:34:03 -0700 Subject: [PATCH 05/13] Forward -Zallow-features inside mod compiler --- src/cargo/core/compiler/compilation.rs | 13 ------------- src/cargo/core/compiler/mod.rs | 11 +++++++++++ 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/cargo/core/compiler/compilation.rs b/src/cargo/core/compiler/compilation.rs index d8361a2d24f..dbde49eb2c3 100644 --- a/src/cargo/core/compiler/compilation.rs +++ b/src/cargo/core/compiler/compilation.rs @@ -338,19 +338,6 @@ impl<'cfg> Compilation<'cfg> { .env("CARGO_PKG_AUTHORS", &pkg.authors().join(":")) .cwd(pkg.root()); - if is_rustc_tool { - if let Some(allow) = &self.config.cli_unstable().allow_features { - let mut arg = String::from("-Zallow-features="); - for (i, a) in allow.iter().enumerate() { - arg.push_str(a); - if i != allow.len() - 1 { - arg.push(','); - } - } - cmd.arg(&arg); - } - } - if self.config.cli_unstable().configurable_env { // Apply any environment variables from the config for (key, value) in self.config.env_config()?.iter() { diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 382e36ce6e0..e4e1d2867eb 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -615,6 +615,7 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult { } add_error_format_and_color(cx, &mut rustdoc, false); + add_allow_features(cx, &mut rustdoc); if let Some(args) = cx.bcx.extra_args_for(unit) { rustdoc.args(args); @@ -697,6 +698,15 @@ fn add_cap_lints(bcx: &BuildContext<'_, '_>, unit: &Unit, cmd: &mut ProcessBuild } } +/// Forward -Zallow-features if it is set for cargo. +fn add_allow_features(cx: &Context<'_, '_>, cmd: &mut ProcessBuilder) { + if let Some(allow) = &cx.bcx.config.cli_unstable().allow_features { + let mut arg = String::from("-Zallow-features="); + let _ = util::iter_join_onto(&mut arg, allow, ","); + cmd.arg(&arg); + } +} + /// Add error-format flags to the command. /// /// Cargo always uses JSON output. This has several benefits, such as being @@ -773,6 +783,7 @@ fn build_base_args( add_path_args(bcx.ws, unit, cmd); add_error_format_and_color(cx, cmd, cx.rmeta_required(unit)); + add_allow_features(cx, cmd); if !test { for crate_type in crate_types.iter() { From 6be9eecb2217b408aa57b326ebb01103dac1650f Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Wed, 31 Mar 2021 12:35:23 -0700 Subject: [PATCH 06/13] Include allowed features in fingerprint If this weren't the case, a user that compiled, and then re-ran cargo with a particular set of allowed features would not see any breakage even if other unstable features were used. The downside of this is that changing allow-features causes a full re-compile, but that still _seems_ like the right thing to do. --- src/cargo/core/compiler/fingerprint.rs | 20 ++++++++++++-------- src/cargo/core/features.rs | 4 ++-- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/cargo/core/compiler/fingerprint.rs b/src/cargo/core/compiler/fingerprint.rs index a5811dd4a08..add7c08115e 100644 --- a/src/cargo/core/compiler/fingerprint.rs +++ b/src/cargo/core/compiler/fingerprint.rs @@ -1327,14 +1327,18 @@ fn calculate_normal(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult>, + pub allow_features: Option>, pub unstable_options: bool, pub no_index_update: bool, From 9837239017420857a276253a61950075e6d2a9f8 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Wed, 31 Mar 2021 12:37:51 -0700 Subject: [PATCH 07/13] Move from match guard to if --- src/cargo/core/features.rs | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/src/cargo/core/features.rs b/src/cargo/core/features.rs index 46a581733e1..78d6c958071 100644 --- a/src/cargo/core/features.rs +++ b/src/cargo/core/features.rs @@ -475,25 +475,17 @@ impl Features { SEE_CHANNELS, see_docs() ), - Status::Unstable - if !config - .cli_unstable() - .allow_features - .as_ref() - .map(|f| f.contains(feature_name)) - .unwrap_or(true) => - { - bail!( - "the feature `{}` is not in the list of allowed features: {:?}", - feature_name, - config - .cli_unstable() - .allow_features - .as_ref() - .expect("!unwrap_or(true) == false") - ) + Status::Unstable => { + if let Some(allow) = &config.cli_unstable().allow_features { + if !allow.contains(feature_name) { + bail!( + "the feature `{}` is not in the list of allowed features: {:?}", + feature_name, + allow, + ); + } + } } - Status::Unstable => {} Status::Removed => bail!( "the cargo feature `{}` has been removed\n\ Remove the feature from Cargo.toml to remove this error.\n\ From dc35abf14cd63f8f73c0375807d510c016f979dc Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Wed, 31 Mar 2021 12:38:07 -0700 Subject: [PATCH 08/13] Sort feature list --- src/cargo/core/features.rs | 43 ++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/src/cargo/core/features.rs b/src/cargo/core/features.rs index 78d6c958071..48e3037a3af 100644 --- a/src/cargo/core/features.rs +++ b/src/cargo/core/features.rs @@ -545,39 +545,42 @@ impl Features { #[derive(Default, Debug, Deserialize)] #[serde(default, rename_all = "kebab-case")] pub struct CliUnstable { - pub print_im_a_teapot: bool, + // Permanently unstable features: pub allow_features: Option>, + pub print_im_a_teapot: bool, - pub unstable_options: bool, - pub no_index_update: bool, - pub avoid_dev_deps: bool, - pub minimal_versions: bool, + // All other unstable features. + // Please keep this list lexiographically ordered. pub advanced_env: bool, - pub config_include: bool, - pub dual_proc_macros: bool, - pub mtime_on_use: bool, - pub named_profiles: bool, + pub avoid_dev_deps: bool, pub binary_dep_depinfo: bool, #[serde(deserialize_with = "deserialize_build_std")] pub build_std: Option>, pub build_std_features: Option>, - pub timings: Option>, - pub doctest_xcompile: bool, + pub config_include: bool, + pub configurable_env: bool, + pub credential_process: bool, pub doctest_in_workspace: bool, - pub panic_abort_tests: bool, - pub jobserver_per_rustc: bool, + pub doctest_xcompile: bool, + pub dual_proc_macros: bool, + pub enable_future_incompat_feature: bool, + pub extra_link_arg: bool, pub features: Option>, - pub separate_nightlies: bool, + pub jobserver_per_rustc: bool, + pub minimal_versions: bool, + pub mtime_on_use: bool, pub multitarget: bool, + pub named_profiles: bool, + pub namespaced_features: bool, + pub no_index_update: bool, + pub panic_abort_tests: bool, + pub patch_in_config: bool, pub rustdoc_map: bool, + pub separate_nightlies: bool, pub terminal_width: Option>, - pub namespaced_features: bool, + pub timings: Option>, + pub unstable_options: bool, pub weak_dep_features: bool, - pub extra_link_arg: bool, - pub patch_in_config: bool, - pub credential_process: bool, - pub configurable_env: bool, - pub enable_future_incompat_feature: bool, } const STABILIZED_COMPILE_PROGRESS: &str = "The progress bar is now always \ From e7ca075193e5069004a033ce4aa5f4bd73dce338 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Wed, 31 Mar 2021 12:38:36 -0700 Subject: [PATCH 09/13] Handle allow-features in add() --- src/cargo/core/features.rs | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/src/cargo/core/features.rs b/src/cargo/core/features.rs index 48e3037a3af..29092dea7da 100644 --- a/src/cargo/core/features.rs +++ b/src/cargo/core/features.rs @@ -647,33 +647,15 @@ impl CliUnstable { ); } let mut warnings = Vec::new(); + // We read flags twice, first to get allowed-features (if specified), + // and then to read the remaining unstable flags. for flag in flags { if flag.starts_with("allow-features=") { self.add(flag, &mut warnings)?; } } - if let Some(allowed) = self.allow_features.take() { - for flag in flags { - let k = flag - .splitn(2, '=') - .next() - .expect("split always yields >=1 item"); - if k == "allow-features" { - } else if allowed.contains(k) { - self.add(flag, &mut warnings)?; - } else { - bail!( - "the feature `{}` is not in the list of allowed features: {:?}", - k, - allowed - ); - } - } - self.allow_features = Some(allowed); - } else { - for flag in flags { - self.add(flag, &mut warnings)?; - } + for flag in flags { + self.add(flag, &mut warnings)?; } Ok(warnings) } @@ -744,6 +726,16 @@ impl CliUnstable { )) }; + if let Some(allowed) = &self.allow_features { + if k != "allow-features" && !allowed.contains(k) { + bail!( + "the feature `{}` is not in the list of allowed features: {:?}", + k, + allowed + ); + } + } + match k { "print-im-a-teapot" => self.print_im_a_teapot = parse_bool(k, v)?, "allow-features" => self.allow_features = Some(parse_features(v).into_iter().collect()), From be333390a4121fdb6f162952d872b3801e8caf92 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Wed, 31 Mar 2021 12:39:09 -0700 Subject: [PATCH 10/13] Print features without Debug --- src/cargo/core/features.rs | 10 +++++----- tests/testsuite/cargo_features.rs | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/cargo/core/features.rs b/src/cargo/core/features.rs index 29092dea7da..0e9b9d0f5d8 100644 --- a/src/cargo/core/features.rs +++ b/src/cargo/core/features.rs @@ -101,7 +101,7 @@ use anyhow::{bail, Error}; use serde::{Deserialize, Serialize}; use crate::util::errors::CargoResult; -use crate::util::{indented_lines, ProcessBuilder}; +use crate::util::{indented_lines, iter_join, ProcessBuilder}; use crate::Config; pub const SEE_CHANNELS: &str = @@ -479,9 +479,9 @@ impl Features { if let Some(allow) = &config.cli_unstable().allow_features { if !allow.contains(feature_name) { bail!( - "the feature `{}` is not in the list of allowed features: {:?}", + "the feature `{}` is not in the list of allowed features: [{}]", feature_name, - allow, + iter_join(allow, ", "), ); } } @@ -729,9 +729,9 @@ impl CliUnstable { if let Some(allowed) = &self.allow_features { if k != "allow-features" && !allowed.contains(k) { bail!( - "the feature `{}` is not in the list of allowed features: {:?}", + "the feature `{}` is not in the list of allowed features: [{}]", k, - allowed + iter_join(allowed, ", ") ); } } diff --git a/tests/testsuite/cargo_features.rs b/tests/testsuite/cargo_features.rs index 7d9eec8fd15..cbc54dd47ee 100644 --- a/tests/testsuite/cargo_features.rs +++ b/tests/testsuite/cargo_features.rs @@ -157,7 +157,7 @@ fn allow_features() { .with_status(101) .with_stderr( "\ -error: the feature `print-im-a-teapot` is not in the list of allowed features: {\"test-dummy-unstable\"} +error: the feature `print-im-a-teapot` is not in the list of allowed features: [test-dummy-unstable] ", ) .run(); @@ -171,7 +171,7 @@ error: the feature `print-im-a-teapot` is not in the list of allowed features: { error: failed to parse manifest at `[..]` Caused by: - the feature `test-dummy-unstable` is not in the list of allowed features: {} + the feature `test-dummy-unstable` is not in the list of allowed features: [] ", ) .run(); @@ -279,7 +279,7 @@ fn allow_features_in_cfg() { .with_status(101) .with_stderr( "\ -error: the feature `unstable-options` is not in the list of allowed features: {[..]} +error: the feature `unstable-options` is not in the list of allowed features: [print-im-a-teapot, test-dummy-unstable] ", ) .run(); @@ -291,7 +291,7 @@ error: the feature `unstable-options` is not in the list of allowed features: {[ .with_status(101) .with_stderr( "\ -error: the feature `print-im-a-teapot` is not in the list of allowed features: {\"test-dummy-unstable\"} +error: the feature `print-im-a-teapot` is not in the list of allowed features: [test-dummy-unstable] ", ) .run(); @@ -305,7 +305,7 @@ error: the feature `print-im-a-teapot` is not in the list of allowed features: { error: failed to parse manifest at `[..]` Caused by: - the feature `test-dummy-unstable` is not in the list of allowed features: {} + the feature `test-dummy-unstable` is not in the list of allowed features: [] ", ) .run(); From 3b23a37acce63d4d38e0ad16c707801527ee9519 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Wed, 31 Mar 2021 12:39:19 -0700 Subject: [PATCH 11/13] Future-proof tests --- tests/testsuite/cargo_features.rs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/tests/testsuite/cargo_features.rs b/tests/testsuite/cargo_features.rs index cbc54dd47ee..c4ddde551b8 100644 --- a/tests/testsuite/cargo_features.rs +++ b/tests/testsuite/cargo_features.rs @@ -148,7 +148,6 @@ fn allow_features() { .masquerade_as_nightly_cargo() .env("RUSTC_BOOTSTRAP", "1") .with_stdout("im-a-teapot = true") - .with_stderr("[FINISHED] [..]") .run(); p.cargo("-Zallow-features=test-dummy-unstable -Zprint-im-a-teapot build") @@ -203,17 +202,7 @@ fn allow_features_to_rustc() { .masquerade_as_nightly_cargo() .env("RUSTC_BOOTSTRAP", "1") .with_status(101) - .with_stderr_contains( - "\ -[COMPILING] a [..] -error[E0725]: the feature `test_2018_feature` is not in the list of allowed features -", - ) - .with_stderr_contains( - "\ -error: could not compile `a` -", - ) + .with_stderr_contains("[..]E0725[..]") .run(); p.cargo("-Zallow-features=test_2018_feature build") From 64771ef8cfe55b26266a2eb22c7d35bdd5f380c8 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Wed, 31 Mar 2021 12:43:59 -0700 Subject: [PATCH 12/13] Fix after merge --- src/cargo/core/compiler/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index c0d514218cc..a1dddf1ad82 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -57,7 +57,7 @@ use crate::core::{Feature, PackageId, Target}; use crate::util::errors::{CargoResult, CargoResultExt, VerboseError}; use crate::util::interning::InternedString; use crate::util::machine_message::{self, Message}; -use crate::util::{add_path_args, internal, profile}; +use crate::util::{add_path_args, internal, iter_join_onto, profile}; use cargo_util::{paths, ProcessBuilder, ProcessError}; const RUSTDOC_CRATE_VERSION_FLAG: &str = "--crate-version"; @@ -702,7 +702,7 @@ fn add_cap_lints(bcx: &BuildContext<'_, '_>, unit: &Unit, cmd: &mut ProcessBuild fn add_allow_features(cx: &Context<'_, '_>, cmd: &mut ProcessBuilder) { if let Some(allow) = &cx.bcx.config.cli_unstable().allow_features { let mut arg = String::from("-Zallow-features="); - let _ = util::iter_join_onto(&mut arg, allow, ","); + let _ = iter_join_onto(&mut arg, allow, ","); cmd.arg(&arg); } } From 8d79a75b319250137ac3101ca7cfb4591426adc7 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Thu, 1 Apr 2021 10:39:05 -0700 Subject: [PATCH 13/13] Don't use RUSTC_BOOTSTRAP for nightly-only tests --- tests/testsuite/cargo_features.rs | 37 ++++++++++++++++--------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/tests/testsuite/cargo_features.rs b/tests/testsuite/cargo_features.rs index c4ddde551b8..fdb7cbffdf4 100644 --- a/tests/testsuite/cargo_features.rs +++ b/tests/testsuite/cargo_features.rs @@ -1,6 +1,6 @@ //! Tests for `cargo-features` definitions. -use cargo_test_support::{project, registry}; +use cargo_test_support::{is_nightly, project, registry}; #[cargo_test] fn feature_required() { @@ -115,6 +115,12 @@ release and is no longer necessary to be listed in the manifest #[cargo_test] fn allow_features() { + if !is_nightly() { + // -Zallow-features on rustc is nightly only + eprintln!("skipping test allow_features without nightly rustc"); + return; + } + let p = project() .file( "Cargo.toml", @@ -131,11 +137,8 @@ fn allow_features() { .file("src/lib.rs", "") .build(); - // NOTE: We need to use RUSTC_BOOTSTRAP here since we also need nightly rustc - p.cargo("-Zallow-features=test-dummy-unstable build") .masquerade_as_nightly_cargo() - .env("RUSTC_BOOTSTRAP", "1") .with_stderr( "\ [COMPILING] a [..] @@ -146,13 +149,11 @@ fn allow_features() { p.cargo("-Zallow-features=test-dummy-unstable,print-im-a-teapot -Zprint-im-a-teapot build") .masquerade_as_nightly_cargo() - .env("RUSTC_BOOTSTRAP", "1") .with_stdout("im-a-teapot = true") .run(); p.cargo("-Zallow-features=test-dummy-unstable -Zprint-im-a-teapot build") .masquerade_as_nightly_cargo() - .env("RUSTC_BOOTSTRAP", "1") .with_status(101) .with_stderr( "\ @@ -163,7 +164,6 @@ error: the feature `print-im-a-teapot` is not in the list of allowed features: [ p.cargo("-Zallow-features= build") .masquerade_as_nightly_cargo() - .env("RUSTC_BOOTSTRAP", "1") .with_status(101) .with_stderr( "\ @@ -178,6 +178,12 @@ Caused by: #[cargo_test] fn allow_features_to_rustc() { + if !is_nightly() { + // -Zallow-features on rustc is nightly only + eprintln!("skipping test allow_features_to_rustc without nightly rustc"); + return; + } + let p = project() .file( "Cargo.toml", @@ -196,18 +202,14 @@ fn allow_features_to_rustc() { ) .build(); - // NOTE: We need to use RUSTC_BOOTSTRAP here since we also need nightly rustc - p.cargo("-Zallow-features= build") .masquerade_as_nightly_cargo() - .env("RUSTC_BOOTSTRAP", "1") .with_status(101) .with_stderr_contains("[..]E0725[..]") .run(); p.cargo("-Zallow-features=test_2018_feature build") .masquerade_as_nightly_cargo() - .env("RUSTC_BOOTSTRAP", "1") .with_stderr( "\ [COMPILING] a [..] @@ -219,6 +221,12 @@ fn allow_features_to_rustc() { #[cargo_test] fn allow_features_in_cfg() { + if !is_nightly() { + // -Zallow-features on rustc is nightly only + eprintln!("skipping test allow_features_in_cfg without nightly rustc"); + return; + } + let p = project() .file( "Cargo.toml", @@ -242,11 +250,8 @@ fn allow_features_in_cfg() { .file("src/lib.rs", "") .build(); - // NOTE: We need to use RUSTC_BOOTSTRAP here since we also need nightly rustc - p.cargo("build") .masquerade_as_nightly_cargo() - .env("RUSTC_BOOTSTRAP", "1") .with_stderr( "\ [COMPILING] a [..] @@ -257,14 +262,12 @@ fn allow_features_in_cfg() { p.cargo("-Zprint-im-a-teapot build") .masquerade_as_nightly_cargo() - .env("RUSTC_BOOTSTRAP", "1") .with_stdout("im-a-teapot = true") .with_stderr("[FINISHED] [..]") .run(); p.cargo("-Zunstable-options build") .masquerade_as_nightly_cargo() - .env("RUSTC_BOOTSTRAP", "1") .with_status(101) .with_stderr( "\ @@ -276,7 +279,6 @@ error: the feature `unstable-options` is not in the list of allowed features: [p // -Zallow-features overrides .cargo/config p.cargo("-Zallow-features=test-dummy-unstable -Zprint-im-a-teapot build") .masquerade_as_nightly_cargo() - .env("RUSTC_BOOTSTRAP", "1") .with_status(101) .with_stderr( "\ @@ -287,7 +289,6 @@ error: the feature `print-im-a-teapot` is not in the list of allowed features: [ p.cargo("-Zallow-features= build") .masquerade_as_nightly_cargo() - .env("RUSTC_BOOTSTRAP", "1") .with_status(101) .with_stderr( "\