diff --git a/src/doc/rustc/src/check-cfg.md b/src/doc/rustc/src/check-cfg.md index 37708bda1f3dc..e30d770b7a812 100644 --- a/src/doc/rustc/src/check-cfg.md +++ b/src/doc/rustc/src/check-cfg.md @@ -1,18 +1,30 @@ # Checking conditional configurations -`rustc` accepts the `--check-cfg` option, which specifies whether to check conditions and how to -check them. The `--check-cfg` option takes a value, called the _check cfg specification_. -This specification has one form: +`rustc` supports checking that every _reachable_[^reachable] `#[cfg]` matches a list of the +expected config names and values. -1. `--check-cfg cfg(...)` mark a configuration and it's expected values as expected. +This can help with verifying that the crate is correctly handling conditional compilation for +different target platforms or features. It ensures that the cfg settings are consistent between +what is intended and what is used, helping to catch potential bugs or errors early in the +development process. -*No implicit expectation is added when using `--cfg`. Users are expected to -pass all expected names and values using the _check cfg specification_.* +In order to accomplish that goal, `rustc` accepts the `--check-cfg` flag, which specifies +whether to check conditions and how to check them. -## The `cfg(...)` form +> **Note:** No implicit expectation is added when using `--cfg`. Users are expected to +pass all expected names and values using the _check cfg specification_. -The `cfg(...)` form enables checking the values within list-valued conditions. It has this -basic form: +[^reachable]: `rustc` promises to at least check reachable `#[cfg]`, and while non-reachable +`#[cfg]` are not currently checked, they may well be checked in the future without it being a +breaking change. + +## Specifying and configuring expected names and values + +To specify and configuring expected names and values, the _check cfg specification_ provides +the `cfg(...)` option which enables specifying for an expected config name and it's expected +values. + +It has this basic form: ```bash rustc --check-cfg 'cfg(name, values("value1", "value2", ... "valueN"))' @@ -20,15 +32,20 @@ rustc --check-cfg 'cfg(name, values("value1", "value2", ... "valueN"))' where `name` is a bare identifier (has no quotes) and each `"value"` term is a quoted literal string. `name` specifies the name of the condition, such as `feature` or `my_cfg`. +`"value"` specify one of the value of that condition name. + +When the `cfg(...)` option is specified, `rustc` will check every[^reachable]: + - `#[cfg(name = "value")]` attribute + - `#[cfg_attr(name = "value")]` attribute + - `#[link(name = "a", cfg(name = "value"))]` attribute + - `cfg!(name = "value")` macro call -When the `cfg(...)` option is specified, `rustc` will check every `#[cfg(name = "value")]` -attribute, `#[cfg_attr(name = "value")]` attribute, `#[link(name = "a", cfg(name = "value"))]` -attribute and `cfg!(name = "value")` macro call. It will check that the `"value"` specified is -present in the list of expected values. If `"value"` is not in it, then `rustc` will report an -`unexpected_cfgs` lint diagnostic. The default diagnostic level for this lint is `Warn`. +> *The command line `--cfg` arguments are currently *NOT* checked but may very well be checked +in the future.* -*The command line `--cfg` arguments are currently *NOT* checked but may very well be checked in -the future.* +`rustc` will check that the `"value"` specified is present in the list of expected values. +If `"value"` is not in it, then `rustc` will report an `unexpected_cfgs` lint diagnostic. +The default diagnostic level for this lint is `Warn`. To check for the _none_ value (ie `#[cfg(foo)]`) one can use the `none()` predicate inside `values()`: `values(none())`. It can be followed or preceded by any number of `"value"`. @@ -43,12 +60,12 @@ rustc --check-cfg 'cfg(name, values(none()))' To enable checking of name but not values, use one of these forms: - - No expected values (_will lint on every value_): + - No expected values (_will lint on every value of `name`_): ```bash rustc --check-cfg 'cfg(name, values())' ``` - - Unknown expected values (_will never lint_): + - Unknown expected values (_will never lint on value of `name`_): ```bash rustc --check-cfg 'cfg(name, values(any()))' ``` @@ -59,16 +76,27 @@ To avoid repeating the same set of values, use this form: rustc --check-cfg 'cfg(name1, ..., nameN, values("value1", "value2", ... "valueN"))' ``` +To enable checking without specifying any names or values, use this form: + +```bash +rustc --check-cfg 'cfg()' +``` + The `--check-cfg cfg(...)` option can be repeated, both for the same condition name and for different names. If it is repeated for the same condition name, then the sets of values for that condition are merged together (precedence is given to `values(any())`). +> To help out an equivalence table between `--cfg` arguments and `--check-cfg` is available +[down below](#equivalence-table-with---cfg). + ## Well known names and values -`rustc` has a internal list of well known names and their corresponding values. -Those well known names and values follows the same stability as what they refer to. +In order to avoid the need for users have to specify configs set by Rust Toolchain, `rustc` +maintains a list of well known names and their corresponding values. + +> Those well known names and values follows the same stability as what they refer to. -Well known names and values checking is always enabled as long as at least one +Well known names and values are implicitly added as long as at least one `--check-cfg` argument is present. As of `2024-04-06T`, the list of known names is as follows: @@ -108,11 +136,9 @@ As of `2024-04-06T`, the list of known names is as follows: Like with `values(any())`, well known names checking can be disabled by passing `cfg(any())` as argument to `--check-cfg`. -## Examples - -### Equivalence table +## Equivalence table with `--cfg` -This table describe the equivalence of a `--cfg` argument to a `--check-cfg` argument. +This table describe the equivalence between a `--cfg` argument to a `--check-cfg` argument. | `--cfg` | `--check-cfg` | |-------------------------------|------------------------------------------------------------| @@ -124,40 +150,42 @@ This table describe the equivalence of a `--cfg` argument to a `--check-cfg` arg | `--cfg foo="1" --cfg bar="2"` | `--check-cfg=cfg(foo, values("1")) --check-cfg=cfg(bar, values("2"))` | | `--cfg foo --cfg foo="bar"` | `--check-cfg=cfg(foo, values(none(), "bar"))` | +## Examples + ### Example: Cargo-like `feature` example Consider this command line: ```bash rustc --check-cfg 'cfg(feature, values("lion", "zebra"))' \ - --cfg 'feature="lion"' -Z unstable-options example.rs + --cfg 'feature="lion"' example.rs ``` -This command line indicates that this crate has two features: `lion` and `zebra`. The `lion` +> This command line indicates that this crate has two features: `lion` and `zebra`. The `lion` feature is enabled, while the `zebra` feature is disabled. -Given the `--check-cfg` arguments, exhaustive checking of names and -values are enabled. -`example.rs`: ```rust -#[cfg(feature = "lion")] // This condition is expected, as "lion" is an expected value of `feature` +#[cfg(feature = "lion")] // This condition is expected, as "lion" is an + // expected value of `feature` fn tame_lion(lion: Lion) {} -#[cfg(feature = "zebra")] // This condition is expected, as "zebra" is an expected value of `feature` - // but the condition will still evaluate to false - // since only --cfg feature="lion" was passed +#[cfg(feature = "zebra")] // This condition is expected, as "zebra" is an expected + // value of `feature` but the condition will evaluate + // to false since only --cfg feature="lion" was passed fn ride_zebra(z: Zebra) {} -#[cfg(feature = "platypus")] // This condition is UNEXPECTED, as "platypus" is NOT an expected value of - // `feature` and will cause a compiler warning (by default). +#[cfg(feature = "platypus")] // This condition is UNEXPECTED, as "platypus" is NOT + // an expected value of `feature` and will cause a + // the compiler to emit the `unexpected_cfgs` lint fn poke_platypus() {} -#[cfg(feechure = "lion")] // This condition is UNEXPECTED, as 'feechure' is NOT a expected condition - // name, no `cfg(feechure, ...)` was passed in `--check-cfg` +#[cfg(feechure = "lion")] // This condition is UNEXPECTED, as 'feechure' is NOT + // a expected condition name, no `cfg(feechure, ...)` + // was passed in `--check-cfg` fn tame_lion() {} -#[cfg(windows = "unix")] // This condition is UNEXPECTED, as while 'windows' is a well known - // condition name, it doesn't expect any values +#[cfg(windows = "unix")] // This condition is UNEXPECTED, as the well known + // 'windows' cfg doesn't expect any values fn tame_windows() {} ``` @@ -166,25 +194,28 @@ fn tame_windows() {} ```bash rustc --check-cfg 'cfg(is_embedded, has_feathers)' \ --check-cfg 'cfg(feature, values("zapping", "lasers"))' \ - --cfg has_feathers --cfg 'feature="zapping"' -Z unstable-options + --cfg has_feathers --cfg 'feature="zapping"' ``` ```rust -#[cfg(is_embedded)] // This condition is expected, as 'is_embedded' was provided in --check-cfg -fn do_embedded() {} // and doesn't take any value +#[cfg(is_embedded)] // This condition is expected, as 'is_embedded' was + // provided in --check-cfg and doesn't take any value +fn do_embedded() {} -#[cfg(has_feathers)] // This condition is expected, as 'has_feathers' was provided in --check-cfg -fn do_features() {} // and doesn't take any value +#[cfg(has_feathers)] // This condition is expected, as 'has_feathers' was + // provided in --check-cfg and doesn't take any value +fn do_features() {} -#[cfg(has_mumble_frotz)] // This condition is UNEXPECTED, as 'has_mumble_frotz' was NEVER provided - // in any --check-cfg arguments +#[cfg(has_mumble_frotz)] // This condition is UNEXPECTED, as 'has_mumble_frotz' + // was NEVER provided in any --check-cfg arguments fn do_mumble_frotz() {} -#[cfg(feature = "lasers")] // This condition is expected, as "lasers" is an expected value of `feature` +#[cfg(feature = "lasers")] // This condition is expected, as "lasers" is an + // expected value of `feature` fn shoot_lasers() {} -#[cfg(feature = "monkeys")] // This condition is UNEXPECTED, as "monkeys" is NOT an expected value of - // `feature` +#[cfg(feature = "monkeys")] // This condition is UNEXPECTED, as "monkeys" is NOT + // an expected value of `feature` fn write_shakespeare() {} ``` @@ -192,24 +223,25 @@ fn write_shakespeare() {} ```bash rustc --check-cfg 'cfg(is_embedded, has_feathers, values(any()))' \ - --cfg has_feathers -Z unstable-options + --cfg has_feathers ``` ```rust -#[cfg(is_embedded)] // This condition is expected, as 'is_embedded' was provided in --check-cfg - // as condition name +#[cfg(is_embedded)] // This condition is expected, as 'is_embedded' was + // provided in --check-cfg as condition name fn do_embedded() {} -#[cfg(has_feathers)] // This condition is expected, as "has_feathers" was provided in --check-cfg - // as condition name +#[cfg(has_feathers)] // This condition is expected, as "has_feathers" was + // provided in --check-cfg as condition name fn do_features() {} -#[cfg(has_feathers = "zapping")] // This condition is expected, as "has_feathers" was provided in - // and because *any* values is expected for 'has_feathers' no +#[cfg(has_feathers = "zapping")] // This condition is expected, as "has_feathers" + // was provided and because *any* values is + // expected for 'has_feathers' no // warning is emitted for the value "zapping" fn do_zapping() {} -#[cfg(has_mumble_frotz)] // This condition is UNEXPECTED, as 'has_mumble_frotz' was not provided - // in any --check-cfg arguments +#[cfg(has_mumble_frotz)] // This condition is UNEXPECTED, as 'has_mumble_frotz' + // was not provided in any --check-cfg arguments fn do_mumble_frotz() {} ``` diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index 7c605333c25d4..3e1ac2fa8ad7b 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -19,9 +19,15 @@ For examples, `--cfg 'verbose'` or `--cfg 'feature="serde"'`. These correspond to `#[cfg(verbose)]` and `#[cfg(feature = "serde")]` respectively. -## `--check-cfg`: enables checking conditional configurations +## `--check-cfg`: configure compile-time checking of conditional compilation + +This flag enables checking conditional configurations of the crate at compile-time, +specifically it helps configure the set of expected cfg names and values, in order +to check that every _reachable_ `#[cfg]` matches the expected config names and values. + +This is different from the `--cfg` flag above which activates some config but do +not expect them. This is useful to prevent stalled conditions, typos, ... -This flag will enable checking conditional configurations. Refer to the [Checking conditional configurations](check-cfg.md) of this book for further details and explanation.