diff --git a/crates/cargo-platform/src/cfg.rs b/crates/cargo-platform/src/cfg.rs index cf7826aa0e98..6f92f236fd8c 100644 --- a/crates/cargo-platform/src/cfg.rs +++ b/crates/cargo-platform/src/cfg.rs @@ -10,6 +10,8 @@ pub enum CfgExpr { All(Vec<CfgExpr>), Any(Vec<CfgExpr>), Value(Cfg), + True, + False, } /// A cfg value. @@ -87,6 +89,8 @@ impl CfgExpr { CfgExpr::All(ref e) => e.iter().all(|e| e.matches(cfg)), CfgExpr::Any(ref e) => e.iter().any(|e| e.matches(cfg)), CfgExpr::Value(ref e) => cfg.contains(e), + CfgExpr::True => true, + CfgExpr::False => false, } } @@ -106,7 +110,7 @@ impl CfgExpr { } Ok(()) } - CfgExpr::Value(_) => Ok(()), + CfgExpr::Value(_) | CfgExpr::True | CfgExpr::False => Ok(()), } } @@ -137,6 +141,8 @@ impl fmt::Display for CfgExpr { CfgExpr::All(ref e) => write!(f, "all({})", CommaSep(e)), CfgExpr::Any(ref e) => write!(f, "any({})", CommaSep(e)), CfgExpr::Value(ref e) => write!(f, "{}", e), + CfgExpr::True => write!(f, "true"), + CfgExpr::False => write!(f, "false"), } } } @@ -191,7 +197,11 @@ impl<'a> Parser<'a> { self.eat(&Token::RightParen)?; Ok(CfgExpr::Not(Box::new(e))) } - Some(Ok(..)) => self.cfg().map(CfgExpr::Value), + Some(Ok(..)) => self.cfg().map(|v| match v { + Cfg::Name(n) if n == "true" => CfgExpr::True, + Cfg::Name(n) if n == "false" => CfgExpr::False, + v => CfgExpr::Value(v), + }), Some(Err(..)) => Err(self.t.next().unwrap().err().unwrap()), None => Err(ParseError::new( self.t.orig, diff --git a/crates/cargo-platform/src/lib.rs b/crates/cargo-platform/src/lib.rs index 71e9140bae9c..ba93f7981abf 100644 --- a/crates/cargo-platform/src/lib.rs +++ b/crates/cargo-platform/src/lib.rs @@ -97,6 +97,7 @@ impl Platform { )) }, } + CfgExpr::True | CfgExpr::False => {}, } } diff --git a/src/cargo/core/features.rs b/src/cargo/core/features.rs index 3dc2a1d8e9c8..ab4151383cc3 100644 --- a/src/cargo/core/features.rs +++ b/src/cargo/core/features.rs @@ -516,6 +516,9 @@ features! { /// Allow paths that resolve relatively to a base specified in the config. (unstable, path_bases, "", "reference/unstable.html#path-bases"), + + /// Allow boolean literals in `[target.'cfg(<true/false>)']` + (unstable, cfg_boolean_literals, "", "reference/unstable.html#cfg-boolean-literals"), } /// Status and metadata for a single unstable feature. @@ -760,6 +763,7 @@ unstable_cli_options!( build_std: Option<Vec<String>> = ("Enable Cargo to compile the standard library itself as part of a crate graph compilation"), build_std_features: Option<Vec<String>> = ("Configure features enabled for the standard library itself when building the standard library"), cargo_lints: bool = ("Enable the `[lints.cargo]` table"), + cfg_boolean_literals: bool = ("Allow boolean literals in `[target.'cfg(<true/false>)']`"), codegen_backend: bool = ("Enable the `codegen-backend` option in profiles in .cargo/config.toml file"), config_include: bool = ("Enable the `include` key in config files"), direct_minimal_versions: bool = ("Resolve minimal dependency versions instead of maximum (direct dependencies only)"), @@ -1255,6 +1259,7 @@ impl CliUnstable { } "build-std-features" => self.build_std_features = Some(parse_features(v)), "cargo-lints" => self.cargo_lints = parse_empty(k, v)?, + "cfg-boolean-literals" => self.cfg_boolean_literals = parse_empty(k, v)?, "codegen-backend" => self.codegen_backend = parse_empty(k, v)?, "config-include" => self.config_include = parse_empty(k, v)?, "direct-minimal-versions" => self.direct_minimal_versions = parse_empty(k, v)?, diff --git a/src/cargo/util/context/target.rs b/src/cargo/util/context/target.rs index f306ecc1731b..dbd5ad622c82 100644 --- a/src/cargo/util/context/target.rs +++ b/src/cargo/util/context/target.rs @@ -1,6 +1,7 @@ use super::{ConfigKey, ConfigRelativePath, GlobalContext, OptValue, PathAndArgs, StringList, CV}; use crate::core::compiler::{BuildOutput, LinkArgTarget}; use crate::util::CargoResult; +use cargo_platform::{CfgExpr, Platform}; use serde::Deserialize; use std::collections::{BTreeMap, HashMap}; use std::path::PathBuf; @@ -53,6 +54,17 @@ pub(super) fn load_target_cfgs( let target: BTreeMap<String, TargetCfgConfig> = gctx.get("target")?; tracing::debug!("Got all targets {:#?}", target); for (key, cfg) in target { + // Feature gate `cfg(true)`/`cfg(false)` under `-Zcfg-boolean-literals` + if !gctx.cli_unstable().cfg_boolean_literals { + if let Ok(Platform::Cfg(cfg_expr)) = key.parse() { + cfg_expr.walk_expr(|e| match e { + CfgExpr::True | CfgExpr::False => { + anyhow::bail!("`-Zcfg-boolean-literals` should be used to enable cfg boolean literals in `.cargo/config.toml`") + }, + _ => Ok(()), + })?; + } + } if key.starts_with("cfg(") { // Unfortunately this is not able to display the location of the // unused key. Using config::Value<toml::Value> doesn't work. One diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index f4cd2ec7bacd..e8f6dfc8c3f4 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -8,7 +8,7 @@ use std::str::{self, FromStr}; use crate::core::summary::MissingDependencyError; use crate::AlreadyPrintedError; use anyhow::{anyhow, bail, Context as _}; -use cargo_platform::Platform; +use cargo_platform::{CfgExpr, Platform}; use cargo_util::paths::{self, normalize_path}; use cargo_util_schemas::manifest::{ self, PackageName, PathBaseName, TomlDependency, TomlDetailedDependency, TomlManifest, @@ -1326,6 +1326,12 @@ pub fn to_real_manifest( for (name, platform) in original_toml.target.iter().flatten() { let platform_kind: Platform = name.parse()?; platform_kind.check_cfg_attributes(warnings); + if let Platform::Cfg(cfg_expr) = &platform_kind { + cfg_expr.walk_expr(|e| match e { + CfgExpr::True | CfgExpr::False => features.require(Feature::cfg_boolean_literals()), + _ => Ok(()), + })?; + } let platform_kind = Some(platform_kind); validate_dependencies( platform.dependencies.as_ref(), diff --git a/src/doc/src/reference/unstable.md b/src/doc/src/reference/unstable.md index 1b92ffbaf67f..06ca4336efd0 100644 --- a/src/doc/src/reference/unstable.md +++ b/src/doc/src/reference/unstable.md @@ -118,6 +118,7 @@ Each new feature described below should explain how to use it. * [lockfile-path](#lockfile-path) --- Allows to specify a path to lockfile other than the default path `<workspace_root>/Cargo.lock`. * [package-workspace](#package-workspace) --- Allows for packaging and publishing multiple crates in a workspace. * [native-completions](#native-completions) --- Move cargo shell completions to native completions. + * [cfg-boolean-literals](#cfg-boolean-literals) --- Allows the use of boolean literals in `[target.'cfg(<true/false>)']` ## allow-features @@ -1747,6 +1748,29 @@ When in doubt, you can discuss this in [#14520](https://github.com/rust-lang/car - powershell: Add `CARGO_COMPLETE=powershell cargo +nightly | Invoke-Expression` to `$PROFILE`. +## cfg-boolean-literals + +* Tracking Issue: [#00000](https://github.com/rust-lang/cargo/issues/00000) + +This feature allows the use of boolean literals in `[target.'cfg(<true/false>)']`. + +Those boolean literals always evaluate to true and false respectively, they are **not** subject +to `RUSTFLAGS`. + +For example, in this example the `b` dependencies is always compiled, while `c` is never: + +```toml +cargo-features = ["cfg-boolean-literals"] + +[target.'cfg(true)'.dependencies] +b = { path = 'b' } + +[target.'cfg(false)'.dependencies] +c = { path = 'c' } +``` + +For cfgs in `.cargo/config.toml`, `-Zcfg-boolean-literals` must be used. + # Stabilized and removed features ## Compile progress diff --git a/tests/testsuite/cargo/z_help/stdout.term.svg b/tests/testsuite/cargo/z_help/stdout.term.svg index e5386620e464..3a553ee6db07 100644 --- a/tests/testsuite/cargo/z_help/stdout.term.svg +++ b/tests/testsuite/cargo/z_help/stdout.term.svg @@ -1,4 +1,4 @@ -<svg width="1230px" height="722px" xmlns="http://www.w3.org/2000/svg"> +<svg width="1230px" height="740px" xmlns="http://www.w3.org/2000/svg"> <style> .fg { fill: #AAAAAA } .bg { background: #000000 } @@ -36,63 +36,65 @@ </tspan> <tspan x="10px" y="190px"><tspan> -Z cargo-lints Enable the `[lints.cargo]` table</tspan> </tspan> - <tspan x="10px" y="208px"><tspan> -Z codegen-backend Enable the `codegen-backend` option in profiles in .cargo/config.toml file</tspan> + <tspan x="10px" y="208px"><tspan> -Z cfg-boolean-literals Allow boolean literals in `[target.'cfg(<true/false>)']`</tspan> </tspan> - <tspan x="10px" y="226px"><tspan> -Z config-include Enable the `include` key in config files</tspan> + <tspan x="10px" y="226px"><tspan> -Z codegen-backend Enable the `codegen-backend` option in profiles in .cargo/config.toml file</tspan> </tspan> - <tspan x="10px" y="244px"><tspan> -Z direct-minimal-versions Resolve minimal dependency versions instead of maximum (direct dependencies only)</tspan> + <tspan x="10px" y="244px"><tspan> -Z config-include Enable the `include` key in config files</tspan> </tspan> - <tspan x="10px" y="262px"><tspan> -Z doctest-xcompile Compile and run doctests for non-host target using runner config</tspan> + <tspan x="10px" y="262px"><tspan> -Z direct-minimal-versions Resolve minimal dependency versions instead of maximum (direct dependencies only)</tspan> </tspan> - <tspan x="10px" y="280px"><tspan> -Z dual-proc-macros Build proc-macros for both the host and the target</tspan> + <tspan x="10px" y="280px"><tspan> -Z doctest-xcompile Compile and run doctests for non-host target using runner config</tspan> </tspan> - <tspan x="10px" y="298px"><tspan> -Z gc Track cache usage and "garbage collect" unused files</tspan> + <tspan x="10px" y="298px"><tspan> -Z dual-proc-macros Build proc-macros for both the host and the target</tspan> </tspan> - <tspan x="10px" y="316px"><tspan> -Z git Enable support for shallow git fetch operations</tspan> + <tspan x="10px" y="316px"><tspan> -Z gc Track cache usage and "garbage collect" unused files</tspan> </tspan> - <tspan x="10px" y="334px"><tspan> -Z gitoxide Use gitoxide for the given git interactions, or all of them if no argument is given</tspan> + <tspan x="10px" y="334px"><tspan> -Z git Enable support for shallow git fetch operations</tspan> </tspan> - <tspan x="10px" y="352px"><tspan> -Z host-config Enable the `[host]` section in the .cargo/config.toml file</tspan> + <tspan x="10px" y="352px"><tspan> -Z gitoxide Use gitoxide for the given git interactions, or all of them if no argument is given</tspan> </tspan> - <tspan x="10px" y="370px"><tspan> -Z minimal-versions Resolve minimal dependency versions instead of maximum</tspan> + <tspan x="10px" y="370px"><tspan> -Z host-config Enable the `[host]` section in the .cargo/config.toml file</tspan> </tspan> - <tspan x="10px" y="388px"><tspan> -Z msrv-policy Enable rust-version aware policy within cargo</tspan> + <tspan x="10px" y="388px"><tspan> -Z minimal-versions Resolve minimal dependency versions instead of maximum</tspan> </tspan> - <tspan x="10px" y="406px"><tspan> -Z mtime-on-use Configure Cargo to update the mtime of used files</tspan> + <tspan x="10px" y="406px"><tspan> -Z msrv-policy Enable rust-version aware policy within cargo</tspan> </tspan> - <tspan x="10px" y="424px"><tspan> -Z no-index-update Do not update the registry index even if the cache is outdated</tspan> + <tspan x="10px" y="424px"><tspan> -Z mtime-on-use Configure Cargo to update the mtime of used files</tspan> </tspan> - <tspan x="10px" y="442px"><tspan> -Z package-workspace Handle intra-workspace dependencies when packaging</tspan> + <tspan x="10px" y="442px"><tspan> -Z no-index-update Do not update the registry index even if the cache is outdated</tspan> </tspan> - <tspan x="10px" y="460px"><tspan> -Z panic-abort-tests Enable support to run tests with -Cpanic=abort</tspan> + <tspan x="10px" y="460px"><tspan> -Z package-workspace Handle intra-workspace dependencies when packaging</tspan> </tspan> - <tspan x="10px" y="478px"><tspan> -Z profile-rustflags Enable the `rustflags` option in profiles in .cargo/config.toml file</tspan> + <tspan x="10px" y="478px"><tspan> -Z panic-abort-tests Enable support to run tests with -Cpanic=abort</tspan> </tspan> - <tspan x="10px" y="496px"><tspan> -Z public-dependency Respect a dependency's `public` field in Cargo.toml to control public/private dependencies</tspan> + <tspan x="10px" y="496px"><tspan> -Z profile-rustflags Enable the `rustflags` option in profiles in .cargo/config.toml file</tspan> </tspan> - <tspan x="10px" y="514px"><tspan> -Z publish-timeout Enable the `publish.timeout` key in .cargo/config.toml file</tspan> + <tspan x="10px" y="514px"><tspan> -Z public-dependency Respect a dependency's `public` field in Cargo.toml to control public/private dependencies</tspan> </tspan> - <tspan x="10px" y="532px"><tspan> -Z rustdoc-map Allow passing external documentation mappings to rustdoc</tspan> + <tspan x="10px" y="532px"><tspan> -Z publish-timeout Enable the `publish.timeout` key in .cargo/config.toml file</tspan> </tspan> - <tspan x="10px" y="550px"><tspan> -Z rustdoc-scrape-examples Allows Rustdoc to scrape code examples from reverse-dependencies</tspan> + <tspan x="10px" y="550px"><tspan> -Z rustdoc-map Allow passing external documentation mappings to rustdoc</tspan> </tspan> - <tspan x="10px" y="568px"><tspan> -Z script Enable support for single-file, `.rs` packages</tspan> + <tspan x="10px" y="568px"><tspan> -Z rustdoc-scrape-examples Allows Rustdoc to scrape code examples from reverse-dependencies</tspan> </tspan> - <tspan x="10px" y="586px"><tspan> -Z target-applies-to-host Enable the `target-applies-to-host` key in the .cargo/config.toml file</tspan> + <tspan x="10px" y="586px"><tspan> -Z script Enable support for single-file, `.rs` packages</tspan> </tspan> - <tspan x="10px" y="604px"><tspan> -Z trim-paths Enable the `trim-paths` option in profiles</tspan> + <tspan x="10px" y="604px"><tspan> -Z target-applies-to-host Enable the `target-applies-to-host` key in the .cargo/config.toml file</tspan> </tspan> - <tspan x="10px" y="622px"><tspan> -Z unstable-options Allow the usage of unstable options</tspan> + <tspan x="10px" y="622px"><tspan> -Z trim-paths Enable the `trim-paths` option in profiles</tspan> </tspan> - <tspan x="10px" y="640px"> + <tspan x="10px" y="640px"><tspan> -Z unstable-options Allow the usage of unstable options</tspan> </tspan> - <tspan x="10px" y="658px"><tspan>Run with `cargo -Z [FLAG] [COMMAND]`</tspan> + <tspan x="10px" y="658px"> </tspan> - <tspan x="10px" y="676px"> + <tspan x="10px" y="676px"><tspan>Run with `cargo -Z [FLAG] [COMMAND]`</tspan> </tspan> - <tspan x="10px" y="694px"><tspan>See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html for more information about these flags.</tspan> + <tspan x="10px" y="694px"> </tspan> - <tspan x="10px" y="712px"> + <tspan x="10px" y="712px"><tspan>See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html for more information about these flags.</tspan> +</tspan> + <tspan x="10px" y="730px"> </tspan> </text> diff --git a/tests/testsuite/cfg.rs b/tests/testsuite/cfg.rs index 54bbf8b7d329..de232b1e9a11 100644 --- a/tests/testsuite/cfg.rs +++ b/tests/testsuite/cfg.rs @@ -549,13 +549,18 @@ fn cfg_booleans_gate() { .build(); p.cargo("check") - // FIXME: true/false should error out as they are gated .with_stderr_data(str![[r#" -[LOCKING] 2 packages to latest compatible versions -[CHECKING] a v0.0.1 ([ROOT]/foo) -[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s +[ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` + +Caused by: + feature `cfg-boolean-literals` is required + + The package requires the Cargo feature called `cfg-boolean-literals`, but that feature is not stabilized in this version of Cargo (1.[..]). + Consider trying a newer version of Cargo (this may require the nightly release). + See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#cfg-boolean-literals for more information about the status of this feature. "#]]) + .with_status(101) .run(); } @@ -582,12 +587,11 @@ fn cfg_booleans_gate_config() { .build(); p.cargo("check") - // FIXME: true/false should error out as they are gated .with_stderr_data(str![[r#" -[CHECKING] a v0.0.1 ([ROOT]/foo) -[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s +[ERROR] `-Zcfg-boolean-literals` should be used to enable cfg boolean literals in `.cargo/config.toml` "#]]) + .with_status(101) .run(); } @@ -597,6 +601,8 @@ fn cfg_booleans() { .file( "Cargo.toml", r#" + cargo-features = ["cfg-boolean-literals"] + [package] name = "a" version = "0.0.1" @@ -618,9 +624,10 @@ fn cfg_booleans() { .build(); p.cargo("check") - // FIXME: `b` should be compiled + .masquerade_as_nightly_cargo(&["cfg-boolean-literals feature"]) .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions +[CHECKING] b v0.0.1 ([ROOT]/foo/b) [CHECKING] a v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s @@ -650,7 +657,8 @@ fn cfg_booleans_config() { ) .build(); - p.cargo("check") + p.cargo("check -Zcfg-boolean-literals") + .masquerade_as_nightly_cargo(&["cfg-boolean-literals feature"]) .with_stderr_data(str![[r#" [CHECKING] a v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s @@ -665,6 +673,8 @@ fn cfg_booleans_not() { .file( "Cargo.toml", r#" + cargo-features = ["cfg-boolean-literals"] + [package] name = "a" version = "0.0.1" @@ -681,6 +691,7 @@ fn cfg_booleans_not() { .build(); p.cargo("check") + .masquerade_as_nightly_cargo(&["cfg-boolean-literals feature"]) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [CHECKING] b v0.0.1 ([ROOT]/foo/b) @@ -697,6 +708,8 @@ fn cfg_booleans_combinators() { .file( "Cargo.toml", r#" + cargo-features = ["cfg-boolean-literals"] + [package] name = "a" version = "0.0.1" @@ -713,9 +726,10 @@ fn cfg_booleans_combinators() { .build(); p.cargo("check") - // FIXME: `b` should be compiled + .masquerade_as_nightly_cargo(&["cfg-boolean-literals feature"]) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version +[CHECKING] b v0.0.1 ([ROOT]/foo/b) [CHECKING] a v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s @@ -729,6 +743,8 @@ fn cfg_booleans_rustflags_no_effect() { .file( "Cargo.toml", r#" + cargo-features = ["cfg-boolean-literals"] + [package] name = "a" version = "0.0.1" @@ -750,15 +766,14 @@ fn cfg_booleans_rustflags_no_effect() { .build(); p.cargo("check") - // FIXME: only `b` should be compiled, the rustflags don't take effect + .masquerade_as_nightly_cargo(&["cfg-boolean-literals feature"]) .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [CHECKING] b v0.0.1 ([ROOT]/foo/b) -[CHECKING] c v0.0.1 ([ROOT]/foo/c) [CHECKING] a v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) - .env("RUSTFLAGS", "--cfg true --cfg false") + .env("RUSTFLAGS", "--cfg false") .run(); }