Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add -Zallow-features to match rustc's -Z #9283

Merged
merged 15 commits into from
Apr 2, 2021
1 change: 1 addition & 0 deletions src/bin/cargo/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 12 additions & 8 deletions src/cargo/core/compiler/fingerprint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1327,14 +1327,18 @@ fn calculate_normal(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Finger
// Include metadata since it is exposed as environment variables.
let m = unit.pkg.manifest().metadata();
let metadata = util::hash_u64((&m.authors, &m.description, &m.homepage, &m.repository));
let config = if unit.mode.is_doc() && cx.bcx.config.cli_unstable().rustdoc_map {
cx.bcx
.config
.doc_extern_map()
.map_or(0, |map| util::hash_u64(map))
} else {
0
};
let mut config = 0u64;
if unit.mode.is_doc() && cx.bcx.config.cli_unstable().rustdoc_map {
config = config.wrapping_add(
cx.bcx
.config
.doc_extern_map()
.map_or(0, |map| util::hash_u64(map)),
);
}
if let Some(allow_features) = &cx.bcx.config.cli_unstable().allow_features {
config = config.wrapping_add(util::hash_u64(allow_features));
}
let compile_kind = unit.kind.fingerprint_hash();
Ok(Fingerprint {
rustc: util::hash_u64(&cx.bcx.rustc().verbose_version),
Expand Down
13 changes: 12 additions & 1 deletion src/cargo/core/compiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -615,6 +615,7 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Work> {
}

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);
Expand Down Expand Up @@ -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 _ = 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
Expand Down Expand Up @@ -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() {
Expand Down
86 changes: 63 additions & 23 deletions src/cargo/core/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
//! of that page. Update the rest of the documentation to add the new
//! feature.

use std::collections::BTreeSet;
use std::env;
use std::fmt;
use std::str::FromStr;
Expand All @@ -101,7 +102,7 @@ use cargo_util::ProcessBuilder;
use serde::{Deserialize, Serialize};

use crate::util::errors::CargoResult;
use crate::util::indented_lines;
use crate::util::{indented_lines, iter_join};
use crate::Config;

pub const SEE_CHANNELS: &str =
Expand Down Expand Up @@ -416,13 +417,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<String>) -> CargoResult<()> {
fn add(
&mut self,
feature_name: &str,
config: &Config,
warnings: &mut Vec<String>,
) -> CargoResult<()> {
let nightly_features_allowed = self.nightly_features_allowed;
let (slot, feature) = match self.status(feature_name) {
Some(p) => p,
Expand Down Expand Up @@ -470,7 +476,17 @@ impl Features {
SEE_CHANNELS,
see_docs()
),
Status::Unstable => {}
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,
iter_join(allow, ", "),
);
}
}
}
Status::Removed => bail!(
"the cargo feature `{}` has been removed\n\
Remove the feature from Cargo.toml to remove this error.\n\
Expand Down Expand Up @@ -530,37 +546,42 @@ impl Features {
#[derive(Default, Debug, Deserialize)]
#[serde(default, rename_all = "kebab-case")]
pub struct CliUnstable {
// Permanently unstable features:
pub allow_features: Option<BTreeSet<String>>,
pub print_im_a_teapot: bool,
pub unstable_options: bool,
pub no_index_update: bool,
pub avoid_dev_deps: bool,
pub minimal_versions: bool,

ehuss marked this conversation as resolved.
Show resolved Hide resolved
// 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<Vec<String>>,
pub build_std_features: Option<Vec<String>>,
pub timings: Option<Vec<String>>,
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<Vec<String>>,
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<Option<usize>>,
pub namespaced_features: bool,
pub timings: Option<Vec<String>>,
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 \
Expand Down Expand Up @@ -627,6 +648,13 @@ 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)?;
}
}
for flag in flags {
self.add(flag, &mut warnings)?;
}
Expand Down Expand Up @@ -656,6 +684,7 @@ impl CliUnstable {
fn parse_features(value: Option<&str>) -> Vec<String> {
match value {
None => Vec::new(),
Some("") => Vec::new(),
ehuss marked this conversation as resolved.
Show resolved Hide resolved
Some(v) => v.split(',').map(|s| s.to_string()).collect(),
}
}
Expand Down Expand Up @@ -698,8 +727,19 @@ 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,
iter_join(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()),
"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)?,
Expand Down
27 changes: 27 additions & 0 deletions src/cargo/util/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::fmt;
use std::time::Duration;

pub use self::canonical_url::CanonicalUrl;
Expand Down Expand Up @@ -65,6 +66,32 @@ pub fn elapsed(duration: Duration) -> String {
}
}

pub fn iter_join_onto<W, I, T>(mut w: W, iter: I, delim: &str) -> fmt::Result
where
W: fmt::Write,
I: IntoIterator<Item = T>,
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<I, T>(iter: I, delim: &str) -> String
where
I: IntoIterator<Item = T>,
T: std::fmt::Display,
{
let mut s = String::new();
let _ = iter_join_onto(&mut s, iter, delim);
s
}

pub fn indented_lines(text: &str) -> String {
text.lines()
.map(|line| {
Expand Down
26 changes: 26 additions & 0 deletions src/doc/src/reference/unstable.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,32 @@ 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`.

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)

Expand Down
Loading