|
| 1 | +# `check-cfg` |
| 2 | + |
| 3 | +The tracking issue for this feature is: [#82450](https://github.com/rust-lang/rust/issues/82450). |
| 4 | + |
| 5 | +------------------------ |
| 6 | + |
| 7 | +This feature allows you to enable complete or partial checking of configuration. |
| 8 | + |
| 9 | +`rustc` accepts the `--check-cfg` option, which specifies whether to check conditions and how to |
| 10 | +check them. The `--check-cfg` option takes a value, called the _check cfg specification_. The |
| 11 | +check cfg specification is parsed using the Rust metadata syntax, just as the `--cfg` option is. |
| 12 | + |
| 13 | +`--check-cfg` option can take one of two forms: |
| 14 | + |
| 15 | +1. `--check-cfg names(...)` enables checking condition names. |
| 16 | +2. `--check-cfg values(...)` enables checking the values within list-valued conditions. |
| 17 | + |
| 18 | +These two options are independent. `names` checks only the namespace of condition names |
| 19 | +while `values` checks only the namespace of the values of list-valued conditions. |
| 20 | + |
| 21 | +## The `names(...)` form |
| 22 | + |
| 23 | +The `names(...)` form enables checking the names. This form uses a named list: |
| 24 | + |
| 25 | +```bash |
| 26 | +rustc --check-cfg 'names(name1, name2, ... nameN)' |
| 27 | +``` |
| 28 | + |
| 29 | +where each `name` is a bare identifier (has no quotes). The order of the names is not significant. |
| 30 | + |
| 31 | +If `--check-cfg names(...)` is specified at least once, then `rustc` will check all references to |
| 32 | +condition names. `rustc` will check every `#[cfg]` attribute, `#[cfg_attr]` attribute, `cfg` clause |
| 33 | +inside `#[link]` attribute and `cfg!(...)` call against the provided list of expected condition |
| 34 | +names. If a name is not present in this list, then `rustc` will report an `unexpected_cfgs` lint |
| 35 | +diagnostic. The default diagnostic level for this lint is `Warn`. |
| 36 | + |
| 37 | +If `--check-cfg names(...)` is not specified, then `rustc` will not check references to condition |
| 38 | +names. |
| 39 | + |
| 40 | +`--check-cfg names(...)` may be specified more than once. The result is that the list of valid |
| 41 | +condition names is merged across all options. It is legal for a condition name to be specified |
| 42 | +more than once; redundantly specifying a condition name has no effect. |
| 43 | + |
| 44 | +To enable checking condition names with an empty set of valid condition names, use the following |
| 45 | +form. The parentheses are required. |
| 46 | + |
| 47 | +```bash |
| 48 | +rustc --check-cfg 'names()' |
| 49 | +``` |
| 50 | + |
| 51 | +Note that `--check-cfg 'names()'` is _not_ equivalent to omitting the option entirely. |
| 52 | +The first form enables checking condition names, while specifying that there are no valid |
| 53 | +condition names (outside of the set of well-known names defined by `rustc`). Omitting the |
| 54 | +`--check-cfg 'names(...)'` option does not enable checking condition names. |
| 55 | + |
| 56 | +Conditions that are enabled are implicitly valid; it is unnecessary (but legal) to specify a |
| 57 | +condition name as both enabled and valid. For example, the following invocations are equivalent: |
| 58 | + |
| 59 | +```bash |
| 60 | +# condition names will be checked, and 'has_time_travel' is valid |
| 61 | +rustc --cfg 'has_time_travel' --check-cfg 'names()' |
| 62 | + |
| 63 | +# condition names will be checked, and 'has_time_travel' is valid |
| 64 | +rustc --cfg 'has_time_travel' --check-cfg 'names(has_time_travel)' |
| 65 | +``` |
| 66 | + |
| 67 | +In contrast, the following two invocations are _not_ equivalent: |
| 68 | + |
| 69 | +```bash |
| 70 | +# condition names will not be checked (because there is no --check-cfg names(...)) |
| 71 | +rustc --cfg 'has_time_travel' |
| 72 | + |
| 73 | +# condition names will be checked, and 'has_time_travel' is both valid and enabled. |
| 74 | +rustc --cfg 'has_time_travel' --check-cfg 'names(has_time_travel)' |
| 75 | +``` |
| 76 | + |
| 77 | +## The `values(...)` form |
| 78 | + |
| 79 | +The `values(...)` form enables checking the values within list-valued conditions. It has this |
| 80 | +form: |
| 81 | + |
| 82 | +```bash |
| 83 | +rustc --check-cfg `values(name, "value1", "value2", ... "valueN")' |
| 84 | +``` |
| 85 | +
|
| 86 | +where `name` is a bare identifier (has no quotes) and each `"value"` term is a quoted literal |
| 87 | +string. `name` specifies the name of the condition, such as `feature` or `target_os`. |
| 88 | +
|
| 89 | +When the `values(...)` option is specified, `rustc` will check every `#[cfg(name = "value")]` |
| 90 | +attribute, `#[cfg_attr(name = "value")]` attribute, `#[link(name = "a", cfg(name = "value"))]` |
| 91 | +and `cfg!(name = "value")` call. It will check that the `"value"` specified is present in the |
| 92 | +list of expected values. If `"value"` is not in it, then `rustc` will report an `unexpected_cfgs` |
| 93 | +lint diagnostic. The default diagnostic level for this lint is `Warn`. |
| 94 | +
|
| 95 | +The form `values()` is an error, because it does not specify a condition name. |
| 96 | +
|
| 97 | +To enable checking of values, but to provide an empty set of valid values, use this form: |
| 98 | +
|
| 99 | +```bash |
| 100 | +rustc --check-cfg `values(name)` |
| 101 | +``` |
| 102 | +
|
| 103 | +The `--check-cfg values(...)` option can be repeated, both for the same condition name and for |
| 104 | +different names. If it is repeated for the same condition name, then the sets of values for that |
| 105 | +condition are merged together. |
| 106 | +
|
| 107 | +## Examples |
| 108 | +
|
| 109 | +Consider this command line: |
| 110 | +
|
| 111 | +```bash |
| 112 | +rustc --check-cfg 'names(feature)' \ |
| 113 | + --check-cfg 'values(feature,"lion","zebra")' \ |
| 114 | + --cfg 'feature="lion"' -Z unstable-options \ |
| 115 | + example.rs |
| 116 | +``` |
| 117 | +
|
| 118 | +This command line indicates that this crate has two features: `lion` and `zebra`. The `lion` |
| 119 | +feature is enabled, while the `zebra` feature is disabled. Consider compiling this code: |
| 120 | +
|
| 121 | +```rust |
| 122 | +// This is expected, and tame_lion() will be compiled |
| 123 | +#[cfg(feature = "lion")] |
| 124 | +fn tame_lion(lion: Lion) {} |
| 125 | +
|
| 126 | +// This is expected, and ride_zebra() will NOT be compiled. |
| 127 | +#[cfg(feature = "zebra")] |
| 128 | +fn ride_zebra(zebra: Zebra) {} |
| 129 | +
|
| 130 | +// This is UNEXPECTED, and will cause a compiler warning (by default). |
| 131 | +#[cfg(feature = "platypus")] |
| 132 | +fn poke_platypus() {} |
| 133 | +
|
| 134 | +// This is UNEXPECTED, because 'feechure' is not a known condition name, |
| 135 | +// and will cause a compiler warning (by default). |
| 136 | +#[cfg(feechure = "lion")] |
| 137 | +fn tame_lion() {} |
| 138 | +``` |
| 139 | +
|
| 140 | +> Note: The `--check-cfg names(feature)` option is necessary only to enable checking the condition |
| 141 | +> name, as in the last example. `feature` is a well-known (always-expected) condition name, and so |
| 142 | +> it is not necessary to specify it in a `--check-cfg 'names(...)'` option. That option can be |
| 143 | +> shortened to > `--check-cfg names()` in order to enable checking well-known condition names. |
| 144 | +
|
| 145 | +### Example: Checking condition names, but not values |
| 146 | +
|
| 147 | +```bash |
| 148 | +# This turns on checking for condition names, but not values, such as 'feature' values. |
| 149 | +rustc --check-cfg 'names(is_embedded, has_feathers)' \ |
| 150 | + --cfg has_feathers --cfg 'feature = "zapping"' -Z unstable-options |
| 151 | +``` |
| 152 | +
|
| 153 | +```rust |
| 154 | +#[cfg(is_embedded)] // This is expected as "is_embedded" was provided in names() |
| 155 | +fn do_embedded() {} |
| 156 | +
|
| 157 | +#[cfg(has_feathers)] // This is expected as "has_feathers" was provided in names() |
| 158 | +fn do_features() {} |
| 159 | +
|
| 160 | +#[cfg(has_mumble_frotz)] // This is UNEXPECTED because names checking is enable and |
| 161 | + // "has_mumble_frotz" was not provided in names() |
| 162 | +fn do_mumble_frotz() {} |
| 163 | +
|
| 164 | +#[cfg(feature = "lasers")] // This doesn't raise a warning, because values checking for "feature" |
| 165 | + // was never used |
| 166 | +fn shoot_lasers() {} |
| 167 | +``` |
| 168 | + |
| 169 | +### Example: Checking feature values, but not condition names |
| 170 | + |
| 171 | +```bash |
| 172 | +# This turns on checking for feature values, but not for condition names. |
| 173 | +rustc --check-cfg 'values(feature, "zapping", "lasers")' \ |
| 174 | + --cfg 'feature="zapping"' -Z unstable-options |
| 175 | +``` |
| 176 | + |
| 177 | +```rust |
| 178 | +#[cfg(is_embedded)] // This is doesn't raise a warning, because names checking was not |
| 179 | + // enable (ie not names()) |
| 180 | +fn do_embedded() {} |
| 181 | +
|
| 182 | +#[cfg(has_feathers)] // Same as above, --check-cfg names(...) was never used so no name |
| 183 | + // checking is performed |
| 184 | +fn do_features() {} |
| 185 | +
|
| 186 | +
|
| 187 | +#[cfg(feature = "lasers")] // This is expected, "lasers" is in the values(feature) list |
| 188 | +fn shoot_lasers() {} |
| 189 | +
|
| 190 | +#[cfg(feature = "monkeys")] // This is UNEXPECTED, because "monkeys" is not in the |
| 191 | + // --check-cfg values(feature) list |
| 192 | +fn write_shakespeare() {} |
| 193 | +``` |
| 194 | +
|
| 195 | +### Example: Checking both condition names and feature values |
| 196 | +
|
| 197 | +```bash |
| 198 | +# This turns on checking for feature values and for condition names. |
| 199 | +rustc --check-cfg 'names(is_embedded, has_feathers)' \ |
| 200 | + --check-cfg 'values(feature, "zapping", "lasers")' \ |
| 201 | + --cfg has_feathers --cfg 'feature="zapping"' -Z unstable-options |
| 202 | +``` |
| 203 | +
|
| 204 | +```rust |
| 205 | +#[cfg(is_embedded)] // This is expected because "is_embedded" was provided in names() |
| 206 | +fn do_embedded() {} |
| 207 | +
|
| 208 | +#[cfg(has_feathers)] // This is expected because "has_feathers" was provided in names() |
| 209 | +fn do_features() {} |
| 210 | +
|
| 211 | +#[cfg(has_mumble_frotz)] // This is UNEXPECTED, because has_mumble_frotz is not in the |
| 212 | + // --check-cfg names(...) list |
| 213 | +fn do_mumble_frotz() {} |
| 214 | +
|
| 215 | +#[cfg(feature = "lasers")] // This is expected, "lasers" is in the values(feature) list |
| 216 | +fn shoot_lasers() {} |
| 217 | +
|
| 218 | +#[cfg(feature = "monkeys")] // This is UNEXPECTED, because "monkeys" is not in |
| 219 | + // the values(feature) list |
| 220 | +fn write_shakespear() {} |
| 221 | +``` |
0 commit comments