diff --git a/src/cargo/core/compiler/context/mod.rs b/src/cargo/core/compiler/context/mod.rs index 7efe77ef91f..edd8dc1a8bd 100644 --- a/src/cargo/core/compiler/context/mod.rs +++ b/src/cargo/core/compiler/context/mod.rs @@ -225,6 +225,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> { let mut args = compiler::extern_args(&self, unit, &mut unstable_opts)?; args.extend(compiler::lto_args(&self, unit)); args.extend(compiler::features_args(&self, unit)); + args.extend(compiler::check_cfg_args(&self, unit)); let script_meta = self.find_build_script_metadata(unit); if let Some(meta) = script_meta { diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 5abd06a75bd..a1de4fe9f55 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -646,6 +646,7 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult { rustdoc.arg("-o").arg(&doc_dir); rustdoc.args(&features_args(cx, unit)); + rustdoc.args(&check_cfg_args(cx, unit)); add_error_format_and_color(cx, &mut rustdoc); add_allow_features(cx, &mut rustdoc); @@ -966,6 +967,7 @@ fn build_base_args( } cmd.args(&features_args(cx, unit)); + cmd.args(&check_cfg_args(cx, unit)); let meta = cx.files().metadata(unit); cmd.arg("-C").arg(&format!("metadata={}", meta)); @@ -1039,15 +1041,30 @@ fn build_base_args( Ok(()) } -/// Features with --cfg and all features with --check-cfg -fn features_args(cx: &Context<'_, '_>, unit: &Unit) -> Vec { - let mut args = Vec::with_capacity(unit.features.len() + 2); +/// All active features for the unit passed as --cfg +fn features_args(_cx: &Context<'_, '_>, unit: &Unit) -> Vec { + let mut args = Vec::with_capacity(unit.features.len() * 2); for feat in &unit.features { args.push(OsString::from("--cfg")); args.push(OsString::from(format!("feature=\"{}\"", feat))); } + args +} + +/// Generate the --check-cfg arguments for the unit +fn check_cfg_args(cx: &Context<'_, '_>, unit: &Unit) -> Vec { + if !cx.bcx.config.cli_unstable().check_cfg_features + && !cx.bcx.config.cli_unstable().check_cfg_well_known_names + && !cx.bcx.config.cli_unstable().check_cfg_well_known_values + { + return Vec::new(); + } + + let mut args = Vec::with_capacity(unit.pkg.summary().features().len() * 2 + 4); + args.push(OsString::from("-Zunstable-options")); + if cx.bcx.config.cli_unstable().check_cfg_features { // This generate something like this: // - values(feature) @@ -1060,11 +1077,20 @@ fn features_args(cx: &Context<'_, '_>, unit: &Unit) -> Vec { } arg.push(")"); - args.push(OsString::from("-Zunstable-options")); args.push(OsString::from("--check-cfg")); args.push(arg); } + if cx.bcx.config.cli_unstable().check_cfg_well_known_names { + args.push(OsString::from("--check-cfg")); + args.push(OsString::from("names()")); + } + + if cx.bcx.config.cli_unstable().check_cfg_well_known_values { + args.push(OsString::from("--check-cfg")); + args.push(OsString::from("values()")); + } + args } diff --git a/src/cargo/core/features.rs b/src/cargo/core/features.rs index cc8d0a3cdbe..8be9c34ec9e 100644 --- a/src/cargo/core/features.rs +++ b/src/cargo/core/features.rs @@ -639,6 +639,8 @@ unstable_cli_options!( config_include: bool = ("Enable the `include` key in config files"), credential_process: bool = ("Add a config setting to fetch registry authentication tokens by calling an external process"), check_cfg_features: bool = ("Enable compile-time checking of features in `cfg`"), + check_cfg_well_known_names: bool = ("Enable compile-time checking of well known names in `cfg`"), + check_cfg_well_known_values: bool = ("Enable compile-time checking of well known values in `cfg`"), doctest_in_workspace: bool = ("Compile doctests with paths relative to the workspace root"), doctest_xcompile: bool = ("Compile and run doctests for non-host target using runner config"), dual_proc_macros: bool = ("Build proc-macros for both the host and the target"), @@ -837,6 +839,8 @@ impl CliUnstable { "advanced-env" => self.advanced_env = parse_empty(k, v)?, "config-include" => self.config_include = parse_empty(k, v)?, "check-cfg-features" => self.check_cfg_features = parse_empty(k, v)?, + "check-cfg-well-known-names" => self.check_cfg_well_known_names = parse_empty(k, v)?, + "check-cfg-well-known-values" => self.check_cfg_well_known_values = parse_empty(k, v)?, "dual-proc-macros" => self.dual_proc_macros = parse_empty(k, v)?, // can also be set in .cargo/config or with and ENV "mtime-on-use" => self.mtime_on_use = parse_empty(k, v)?, diff --git a/src/doc/src/reference/unstable.md b/src/doc/src/reference/unstable.md index 1c1db0ba713..0b218b5cedc 100644 --- a/src/doc/src/reference/unstable.md +++ b/src/doc/src/reference/unstable.md @@ -1161,6 +1161,32 @@ For instance: cargo check -Z unstable-options -Z check-cfg-features ``` +### check-cfg-well-known-names + +* RFC: [#3013](https://github.com/rust-lang/rfcs/pull/3013) + +The `-Z check-cfg-well-known-names` argument tells Cargo to activate `rustc` and `rustdoc` unstable +`--check-cfg` command line as `--check-cfg=names()`. +This enables compile time checking of well known names in `#[cfg]`, `cfg!` and `#[cfg_attr]`. +For instance: + +``` +cargo check -Z unstable-options -Z check-cfg-well-known-names +``` + +### check-cfg-well-known-values + +* RFC: [#3013](https://github.com/rust-lang/rfcs/pull/3013) + +The `-Z check-cfg-well-known-values` argument tells Cargo to activate `rustc` and `rustdoc` unstable +`--check-cfg` command line as `--check-cfg=values()`. +This enables compile time checking of well known values in `#[cfg]`, `cfg!` and `#[cfg_attr]`. +For instance: + +``` +cargo check -Z unstable-options -Z check-cfg-well-known-values +``` + ## Stabilized and removed features ### Compile progress diff --git a/tests/testsuite/build.rs b/tests/testsuite/build.rs index c6ab943e4ba..2445493b169 100644 --- a/tests/testsuite/build.rs +++ b/tests/testsuite/build.rs @@ -6389,3 +6389,89 @@ fn check_cfg_features_with_namespaced_features() { ) .run(); } + +#[cfg_attr(windows, ignore)] // weird normalization issue with windows and cargo-test-support +#[cargo_test] +fn check_cfg_well_known_names() { + if !is_nightly() { + // --check-cfg is a nightly only rustc command line + return; + } + + let p = project() + .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) + .file("src/main.rs", "fn main() {}") + .build(); + + p.cargo("build -v -Z check-cfg-well-known-names") + .masquerade_as_nightly_cargo() + .with_stderr( + "\ +[COMPILING] foo v0.1.0 [..] +[RUNNING] `rustc [..] --check-cfg 'names()' [..] +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] +", + ) + .run(); +} + +#[cfg_attr(windows, ignore)] // weird normalization issue with windows and cargo-test-support +#[cargo_test] +fn check_cfg_well_known_values() { + if !is_nightly() { + // --check-cfg is a nightly only rustc command line + return; + } + + let p = project() + .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) + .file("src/main.rs", "fn main() {}") + .build(); + + p.cargo("build -v -Z check-cfg-well-known-values") + .masquerade_as_nightly_cargo() + .with_stderr( + "\ +[COMPILING] foo v0.1.0 [..] +[RUNNING] `rustc [..] --check-cfg 'values()' [..] +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] +", + ) + .run(); +} + +#[cfg_attr(windows, ignore)] // weird normalization issue with windows and cargo-test-support +#[cargo_test] +fn check_cfg_all() { + if !is_nightly() { + // --check-cfg is a nightly only rustc command line + return; + } + + let p = project() + .file( + "Cargo.toml", + r#" + [project] + name = "foo" + version = "0.1.0" + + [features] + f_a = [] + f_b = [] + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + p.cargo("build -v -Z check-cfg-features -Z check-cfg-well-known-names -Z check-cfg-well-known-values") + .masquerade_as_nightly_cargo() + .with_stderr( + "\ +[COMPILING] foo v0.1.0 [..] +[RUNNING] `rustc [..] --check-cfg 'values(feature, \"f_a\", \"f_b\")' --check-cfg 'names()' --check-cfg 'values()' [..] +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] +", + ) + .run(); +} diff --git a/tests/testsuite/check.rs b/tests/testsuite/check.rs index 7ddd65adfbe..303aa01fd38 100644 --- a/tests/testsuite/check.rs +++ b/tests/testsuite/check.rs @@ -1034,3 +1034,53 @@ fn check_cfg_features() { ) .run(); } + +#[cfg_attr(windows, ignore)] // weird normalization issue with windows and cargo-test-support +#[cargo_test] +fn check_cfg_well_known_names() { + if !is_nightly() { + // --check-cfg is a nightly only rustc command line + return; + } + + let p = project() + .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) + .file("src/main.rs", "fn main() {}") + .build(); + + p.cargo("check -v -Z check-cfg-well-known-names") + .masquerade_as_nightly_cargo() + .with_stderr( + "\ +[CHECKING] foo v0.1.0 [..] +[RUNNING] `rustc [..] --check-cfg 'names()' [..] +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] +", + ) + .run(); +} + +#[cfg_attr(windows, ignore)] // weird normalization issue with windows and cargo-test-support +#[cargo_test] +fn check_cfg_well_known_values() { + if !is_nightly() { + // --check-cfg is a nightly only rustc command line + return; + } + + let p = project() + .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) + .file("src/main.rs", "fn main() {}") + .build(); + + p.cargo("check -v -Z check-cfg-well-known-values") + .masquerade_as_nightly_cargo() + .with_stderr( + "\ +[CHECKING] foo v0.1.0 [..] +[RUNNING] `rustc [..] --check-cfg 'values()' [..] +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] +", + ) + .run(); +} diff --git a/tests/testsuite/test.rs b/tests/testsuite/test.rs index cdb2a914304..4c1dc880ba5 100644 --- a/tests/testsuite/test.rs +++ b/tests/testsuite/test.rs @@ -4575,3 +4575,109 @@ fn check_cfg_features_doc() { ) .run(); } + +#[cfg_attr(windows, ignore)] // weird normalization issue with windows and cargo-test-support +#[cargo_test] +fn check_cfg_well_known_names() { + if !is_nightly() { + // --check-cfg is a nightly only rustc command line + return; + } + + let p = project() + .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) + .file("src/main.rs", "fn main() {}") + .build(); + + p.cargo("test -v -Z check-cfg-well-known-names") + .masquerade_as_nightly_cargo() + .with_stderr( + "\ +[COMPILING] foo v0.1.0 [..] +[RUNNING] `rustc [..] --check-cfg 'names()' [..] +[FINISHED] test [unoptimized + debuginfo] target(s) in [..] +[RUNNING] [..] +", + ) + .run(); +} + +#[cfg_attr(windows, ignore)] // weird normalization issue with windows and cargo-test-support +#[cargo_test] +fn check_cfg_well_known_values() { + if !is_nightly() { + // --check-cfg is a nightly only rustc command line + return; + } + + let p = project() + .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) + .file("src/main.rs", "fn main() {}") + .build(); + + p.cargo("test -v -Z check-cfg-well-known-values") + .masquerade_as_nightly_cargo() + .with_stderr( + "\ +[COMPILING] foo v0.1.0 [..] +[RUNNING] `rustc [..] --check-cfg 'values()' [..] +[FINISHED] test [unoptimized + debuginfo] target(s) in [..] +[RUNNING] [..] +", + ) + .run(); +} + +#[cfg_attr(windows, ignore)] // weird normalization issue with windows and cargo-test-support +#[cargo_test] +fn check_cfg_well_known_names_doc() { + if !is_nightly() { + // --check-cfg is a nightly only rustc command line + return; + } + + let p = project() + .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) + .file("src/lib.rs", "#[allow(dead_code)] fn foo() {}") + .build(); + + p.cargo("test -v --doc -Z check-cfg-well-known-names") + .masquerade_as_nightly_cargo() + .with_stderr( + "\ +[COMPILING] foo v0.1.0 [..] +[RUNNING] `rustc [..] --check-cfg 'names()' [..] +[FINISHED] test [unoptimized + debuginfo] target(s) in [..] +[DOCTEST] foo +[RUNNING] `rustdoc [..] --check-cfg 'names()' [..] +", + ) + .run(); +} + +#[cfg_attr(windows, ignore)] // weird normalization issue with windows and cargo-test-support +#[cargo_test] +fn check_cfg_well_known_values_doc() { + if !is_nightly() { + // --check-cfg is a nightly only rustc command line + return; + } + + let p = project() + .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) + .file("src/lib.rs", "#[allow(dead_code)] fn foo() {}") + .build(); + + p.cargo("test -v --doc -Z check-cfg-well-known-values") + .masquerade_as_nightly_cargo() + .with_stderr( + "\ +[COMPILING] foo v0.1.0 [..] +[RUNNING] `rustc [..] --check-cfg 'values()' [..] +[FINISHED] test [unoptimized + debuginfo] target(s) in [..] +[DOCTEST] foo +[RUNNING] `rustdoc [..] --check-cfg 'values()' [..] +", + ) + .run(); +}