mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
Rollup merge of #119282 - Urgau:check-cfg-rework-unstable-doc, r=JohnTitor
Rework and improve the unstable documentation of check-cfg This PR rework and improve the unstable documentation of the check-cfg feature. The goal is to have a simpler to understand documentation with examples that are more practical and less theoretical. As well as making the documentation more explicit about the whereabouts of the feature. `@rustbot` label +T-compiler +F-check-cfg
This commit is contained in:
commit
5c9a8d7bb5
@ -4,18 +4,16 @@ The tracking issue for this feature is: [#82450](https://github.com/rust-lang/ru
|
||||
|
||||
------------------------
|
||||
|
||||
This feature allows you to enable complete or partial checking of configuration.
|
||||
This feature enables checking of conditional configuration.
|
||||
|
||||
`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_. The
|
||||
check cfg specification is parsed using the Rust metadata syntax, just as the `--cfg` option is.
|
||||
check them. The `--check-cfg` option takes a value, called the _check cfg specification_.
|
||||
This specification has one form:
|
||||
|
||||
`--check-cfg` option take one form:
|
||||
1. `--check-cfg cfg(...)` mark a configuration and it's expected values as expected.
|
||||
|
||||
1. `--check-cfg cfg(...)` enables checking the values within list-valued conditions.
|
||||
|
||||
NOTE: No implicit expectation is added when using `--cfg` for both forms. Users are expected to
|
||||
pass all expected names and values using `cfg(...)`.
|
||||
*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
|
||||
|
||||
@ -23,7 +21,7 @@ The `cfg(...)` form enables checking the values within list-valued conditions. I
|
||||
basic form:
|
||||
|
||||
```bash
|
||||
rustc --check-cfg 'cfg(name1, ..., nameN, values("value1", "value2", ... "valueN"))'
|
||||
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
|
||||
@ -31,162 +29,186 @@ string. `name` specifies the name of the condition, such as `feature` or `my_cfg
|
||||
|
||||
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"))]`
|
||||
and `cfg!(name = "value")` 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`.
|
||||
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.*
|
||||
|
||||
To enable checking of values, but to provide an empty set of expected values, use these forms:
|
||||
To enable checking of values, but to provide an *none*/empty set of expected values
|
||||
(ie. expect `#[cfg(name)]`), use these forms:
|
||||
|
||||
```bash
|
||||
rustc --check-cfg 'cfg(name1, ..., nameN)'
|
||||
rustc --check-cfg 'cfg(name1, ..., nameN, values())'
|
||||
rustc --check-cfg 'cfg(name)'
|
||||
rustc --check-cfg 'cfg(name, values())'
|
||||
```
|
||||
|
||||
To enable checking of name but not values (i.e. unknown expected values), use this form:
|
||||
|
||||
```bash
|
||||
rustc --check-cfg 'cfg(name1, ..., nameN, values(any()))'
|
||||
rustc --check-cfg 'cfg(name, values(any()))'
|
||||
```
|
||||
|
||||
To avoid repeating the same set of values, use this form:
|
||||
|
||||
```bash
|
||||
rustc --check-cfg 'cfg(name1, ..., nameN, values("value1", "value2", ... "valueN"))'
|
||||
```
|
||||
|
||||
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 (presedence is given to `any()`).
|
||||
condition are merged together (precedence is given to `values(any())`).
|
||||
|
||||
## 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.
|
||||
|
||||
Well known values checking is always enabled as long as a `--check-cfg` argument is present.
|
||||
Well known names and values checking is always enabled as long as at least one
|
||||
`--check-cfg` argument is present.
|
||||
|
||||
Well known names checking is always enable as long as a `--check-cfg` argument is present
|
||||
**unless** any `cfg(any())` argument is passed.
|
||||
As of `2024-01-09T`, the list of known names is as follows:
|
||||
|
||||
To disable checking of well known names, use this form:
|
||||
<!--- See CheckCfg::fill_well_known in compiler/rustc_session/src/config.rs -->
|
||||
|
||||
```bash
|
||||
rustc --check-cfg 'cfg(any())'
|
||||
```
|
||||
- `debug_assertions`
|
||||
- `doc`
|
||||
- `doctest`
|
||||
- `miri`
|
||||
- `overflow_checks`
|
||||
- `panic`
|
||||
- `proc_macro`
|
||||
- `relocation_model`
|
||||
- `sanitize`
|
||||
- `sanitizer_cfi_generalize_pointers`
|
||||
- `sanitizer_cfi_normalize_integers`
|
||||
- `target_abi`
|
||||
- `target_arch`
|
||||
- `target_endian`
|
||||
- `target_env`
|
||||
- `target_family`
|
||||
- `target_feature`
|
||||
- `target_has_atomic`
|
||||
- `target_has_atomic_equal_alignment`
|
||||
- `target_has_atomic_load_store`
|
||||
- `target_os`
|
||||
- `target_pointer_width`
|
||||
- `target_thread_local`
|
||||
- `target_vendor`
|
||||
- `test`
|
||||
- `unix`
|
||||
- `windows`
|
||||
|
||||
NOTE: If one want to enable values and names checking without having any cfg to declare, one
|
||||
can use an empty `cfg()` argument.
|
||||
Like with `values(any())`, well known names checking can be disabled by passing `cfg(any())`
|
||||
as argument to `--check-cfg`.
|
||||
|
||||
## Examples
|
||||
|
||||
### Equivalence table
|
||||
|
||||
This table describe the equivalence of a `--cfg` argument to a `--check-cfg` argument.
|
||||
|
||||
| `--cfg` | `--check-cfg` |
|
||||
|-----------------------------|----------------------------------------------------------|
|
||||
| *nothing* | *nothing* or `--check-cfg=cfg()` (to enable the checking) |
|
||||
| `--cfg foo` | `--check-cfg=cfg(foo) or --check-cfg=cfg(foo, values())` |
|
||||
| `--cfg foo=""` | `--check-cfg=cfg(foo, values(""))` |
|
||||
| `--cfg foo="bar"` | `--check-cfg=cfg(foo, values("bar"))` |
|
||||
| `--cfg foo="1" --cfg foo="2"` | `--check-cfg=cfg(foo, values("1", "2"))` |
|
||||
| `--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) --check-cfg=cfg(foo, values("bar"))` |
|
||||
|
||||
NOTE: There is (currently) no way to express that a condition name is expected but no (!= none)
|
||||
values are expected. Passing an empty `values()` means *(none)* in the sense of `#[cfg(foo)]`
|
||||
with no value. Users are expected to NOT pass a `--check-cfg` with that condition name.
|
||||
|
||||
### 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"' -Z unstable-options example.rs
|
||||
```
|
||||
|
||||
This command line indicates that this crate has two features: `lion` and `zebra`. The `lion`
|
||||
feature is enabled, while the `zebra` feature is disabled. Exhaustive checking of names and
|
||||
values are enabled by default. Consider compiling this code:
|
||||
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
|
||||
// This is expected, and tame_lion() will be compiled
|
||||
#[cfg(feature = "lion")]
|
||||
#[cfg(feature = "lion")] // This condition is expected, as "lion" is an expected value of `feature`
|
||||
fn tame_lion(lion: Lion) {}
|
||||
|
||||
// This is expected, and ride_zebra() will NOT be compiled.
|
||||
#[cfg(feature = "zebra")]
|
||||
fn ride_zebra(zebra: Zebra) {}
|
||||
#[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
|
||||
fn ride_zebra(z: Zebra) {}
|
||||
|
||||
// This is UNEXPECTED, and will cause a compiler warning (by default).
|
||||
#[cfg(feature = "platypus")]
|
||||
#[cfg(feature = "platypus")] // This condition is UNEXPECTED, as "platypus" is NOT an expected value of
|
||||
// `feature` and will cause a compiler warning (by default).
|
||||
fn poke_platypus() {}
|
||||
|
||||
// This is UNEXPECTED, because 'feechure' is not a known condition name,
|
||||
// and will cause a compiler warning (by default).
|
||||
#[cfg(feechure = "lion")]
|
||||
#[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() {}
|
||||
|
||||
// This is UNEXPECTED, because 'windows' is a well known condition name,
|
||||
// and because 'windows' doesn't take any values,
|
||||
// and will cause a compiler warning (by default).
|
||||
#[cfg(windows = "unix")]
|
||||
#[cfg(windows = "unix")] // This condition is UNEXPECTED, as while 'windows' is a well known
|
||||
// condition name, it doens't expect any values
|
||||
fn tame_windows() {}
|
||||
```
|
||||
|
||||
### Example: Checking condition names, but not values
|
||||
### Example: Multiple names and values
|
||||
|
||||
```bash
|
||||
# This turns on checking for condition names, but not values, such as 'feature' values.
|
||||
rustc --check-cfg 'cfg(is_embedded, has_feathers, values(any()))' \
|
||||
--cfg has_feathers -Z unstable-options
|
||||
```
|
||||
|
||||
```rust
|
||||
#[cfg(is_embedded)] // This is expected as "is_embedded" was provided in cfg()
|
||||
fn do_embedded() {} // and because names exhaustiveness was not disabled
|
||||
|
||||
#[cfg(has_feathers)] // This is expected as "has_feathers" was provided in cfg()
|
||||
fn do_features() {} // and because names exhaustiveness was not disabled
|
||||
|
||||
#[cfg(has_feathers = "zapping")] // This is expected as "has_feathers" was provided in cfg()
|
||||
// and because no value checking was enable for "has_feathers"
|
||||
// no warning is emitted for the value "zapping"
|
||||
fn do_zapping() {}
|
||||
|
||||
#[cfg(has_mumble_frotz)] // This is UNEXPECTED because names checking is enable and
|
||||
// "has_mumble_frotz" was not provided in cfg()
|
||||
fn do_mumble_frotz() {}
|
||||
```
|
||||
|
||||
### Example: Checking feature values, but not condition names
|
||||
|
||||
```bash
|
||||
# This turns on checking for feature values, but not for condition names.
|
||||
rustc --check-cfg 'cfg(feature, values("zapping", "lasers"))' \
|
||||
--check-cfg 'cfg(any())' \
|
||||
--cfg 'feature="zapping"' -Z unstable-options
|
||||
```
|
||||
|
||||
```rust
|
||||
#[cfg(is_embedded)] // This is doesn't raise a warning, because names checking was
|
||||
// disabled by 'cfg(any())'
|
||||
fn do_embedded() {}
|
||||
|
||||
#[cfg(has_feathers)] // Same as above, 'cfg(any())' was provided so no name
|
||||
// checking is performed
|
||||
fn do_features() {}
|
||||
|
||||
#[cfg(feature = "lasers")] // This is expected, "lasers" is in the cfg(feature) list
|
||||
fn shoot_lasers() {}
|
||||
|
||||
#[cfg(feature = "monkeys")] // This is UNEXPECTED, because "monkeys" is not in the
|
||||
// cfg(feature) list
|
||||
fn write_shakespeare() {}
|
||||
```
|
||||
|
||||
### Example: Checking both condition names and feature values
|
||||
|
||||
```bash
|
||||
# This turns on checking for feature values and for condition names.
|
||||
rustc --check-cfg 'cfg(is_embedded, has_feathers)' \
|
||||
--check-cfg 'cfg(feature, values("zapping", "lasers"))' \
|
||||
--cfg has_feathers --cfg 'feature="zapping"' -Z unstable-options
|
||||
```
|
||||
|
||||
```rust
|
||||
#[cfg(is_embedded)] // This is expected because "is_embedded" was provided in cfg()
|
||||
#[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(has_feathers)] // This is expected because "has_feathers" was provided in cfg()
|
||||
fn do_features() {} // and deosn't take any value
|
||||
#[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_mumble_frotz)] // This is UNEXPECTED, because "has_mumble_frotz" was never provided
|
||||
#[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 is expected, "lasers" is in the cfg(feature) list
|
||||
#[cfg(feature = "lasers")] // This condition is expected, as "lasers" is an expected value of `feature`
|
||||
fn shoot_lasers() {}
|
||||
|
||||
#[cfg(feature = "monkeys")] // This is UNEXPECTED, because "monkeys" is not in
|
||||
// the cfg(feature) list
|
||||
#[cfg(feature = "monkeys")] // This condition is UNEXPECTED, as "monkeys" is NOT an expected value of
|
||||
// `feature`
|
||||
fn write_shakespeare() {}
|
||||
```
|
||||
|
||||
### Example: Condition names without values
|
||||
|
||||
```bash
|
||||
rustc --check-cfg 'cfg(is_embedded, has_feathers, values(any()))' \
|
||||
--cfg has_feathers -Z unstable-options
|
||||
```
|
||||
|
||||
```rust
|
||||
#[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
|
||||
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
|
||||
// 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
|
||||
fn do_mumble_frotz() {}
|
||||
```
|
||||
|
Loading…
Reference in New Issue
Block a user