Skip to content

Commit

Permalink
Remove deprecated --check-cfg names() and values() syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
Urgau committed Dec 5, 2023
1 parent 9a94239 commit 3f0369e
Show file tree
Hide file tree
Showing 35 changed files with 173 additions and 397 deletions.
240 changes: 83 additions & 157 deletions compiler/rustc_interface/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ use rustc_data_structures::sync::Lrc;
use rustc_errors::registry::Registry;
use rustc_errors::{ErrorGuaranteed, Handler};
use rustc_lint::LintStore;
use rustc_middle::ty;
use rustc_middle::util::Providers;
use rustc_middle::{bug, ty};
use rustc_parse::maybe_new_parser_from_source_str;
use rustc_query_impl::QueryCtxt;
use rustc_query_system::query::print_query_stack;
Expand Down Expand Up @@ -104,7 +104,6 @@ pub(crate) fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -
let exhaustive_values = !specs.is_empty();
let mut check_cfg = CheckCfg { exhaustive_names, exhaustive_values, ..CheckCfg::default() };

let mut old_syntax = None;
for s in specs {
let sess = ParseSess::with_silent_emitter(Some(format!(
"this error occurred on the command line: `--check-cfg={s}`"
Expand Down Expand Up @@ -142,174 +141,101 @@ pub(crate) fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -
expected_error();
};

let mut set_old_syntax = || {
// defaults are flipped for the old syntax
if old_syntax == None {
check_cfg.exhaustive_names = false;
check_cfg.exhaustive_values = false;
}
old_syntax = Some(true);
};

if meta_item.has_name(sym::names) {
set_old_syntax();

check_cfg.exhaustive_names = true;
for arg in args {
if arg.is_word()
&& let Some(ident) = arg.ident()
{
check_cfg.expecteds.entry(ident.name).or_insert(ExpectedValues::Any);
} else {
error!("`names()` arguments must be simple identifiers");
}
}
} else if meta_item.has_name(sym::values) {
set_old_syntax();

if let Some((name, values)) = args.split_first() {
if name.is_word()
&& let Some(ident) = name.ident()
{
let expected_values = check_cfg
.expecteds
.entry(ident.name)
.and_modify(|expected_values| match expected_values {
ExpectedValues::Some(_) => {}
ExpectedValues::Any => {
// handle the case where names(...) was done
// before values by changing to a list
*expected_values = ExpectedValues::Some(FxHashSet::default());
}
})
.or_insert_with(|| ExpectedValues::Some(FxHashSet::default()));
if !meta_item.has_name(sym::cfg) {
expected_error();
}

let ExpectedValues::Some(expected_values) = expected_values else {
bug!("`expected_values` should be a list a values")
};
let mut names = Vec::new();
let mut values: FxHashSet<_> = Default::default();

for val in values {
if let Some(LitKind::Str(s, _)) = val.lit().map(|lit| &lit.kind) {
expected_values.insert(Some(*s));
} else {
error!("`values()` arguments must be string literals");
}
}
let mut any_specified = false;
let mut values_specified = false;
let mut values_any_specified = false;

if values.is_empty() {
expected_values.insert(None);
}
} else {
error!("`values()` first argument must be a simple identifier");
for arg in args {
if arg.is_word()
&& let Some(ident) = arg.ident()
{
if values_specified {
error!("`cfg()` names cannot be after values");
}
} else if args.is_empty() {
check_cfg.exhaustive_values = true;
} else {
expected_error();
}
} else if meta_item.has_name(sym::cfg) {
old_syntax = Some(false);

let mut names = Vec::new();
let mut values: FxHashSet<_> = Default::default();

let mut any_specified = false;
let mut values_specified = false;
let mut values_any_specified = false;

for arg in args {
if arg.is_word()
&& let Some(ident) = arg.ident()
{
if values_specified {
error!("`cfg()` names cannot be after values");
}
names.push(ident);
} else if arg.has_name(sym::any)
&& let Some(args) = arg.meta_item_list()
{
if any_specified {
error!("`any()` cannot be specified multiple times");
}
any_specified = true;
if !args.is_empty() {
error!("`any()` must be empty");
}
} else if arg.has_name(sym::values)
&& let Some(args) = arg.meta_item_list()
{
if names.is_empty() {
error!("`values()` cannot be specified before the names");
} else if values_specified {
error!("`values()` cannot be specified multiple times");
}
values_specified = true;

for arg in args {
if let Some(LitKind::Str(s, _)) = arg.lit().map(|lit| &lit.kind) {
values.insert(Some(*s));
} else if arg.has_name(sym::any)
&& let Some(args) = arg.meta_item_list()
{
if values_any_specified {
error!("`any()` in `values()` cannot be specified multiple times");
}
values_any_specified = true;
if !args.is_empty() {
error!("`any()` must be empty");
}
} else {
error!("`values()` arguments must be string literals or `any()`");
names.push(ident);
} else if arg.has_name(sym::any)
&& let Some(args) = arg.meta_item_list()
{
if any_specified {
error!("`any()` cannot be specified multiple times");
}
any_specified = true;
if !args.is_empty() {
error!("`any()` must be empty");
}
} else if arg.has_name(sym::values)
&& let Some(args) = arg.meta_item_list()
{
if names.is_empty() {
error!("`values()` cannot be specified before the names");
} else if values_specified {
error!("`values()` cannot be specified multiple times");
}
values_specified = true;

for arg in args {
if let Some(LitKind::Str(s, _)) = arg.lit().map(|lit| &lit.kind) {
values.insert(Some(*s));
} else if arg.has_name(sym::any)
&& let Some(args) = arg.meta_item_list()
{
if values_any_specified {
error!("`any()` in `values()` cannot be specified multiple times");
}
values_any_specified = true;
if !args.is_empty() {
error!("`any()` must be empty");
}
} else {
error!("`values()` arguments must be string literals or `any()`");
}
} else {
error!(
"`cfg()` arguments must be simple identifiers, `any()` or `values(...)`"
);
}
} else {
error!("`cfg()` arguments must be simple identifiers, `any()` or `values(...)`");
}
}

if values.is_empty() && !values_any_specified && !any_specified {
values.insert(None);
} else if !values.is_empty() && values_any_specified {
error!(
"`values()` arguments cannot specify string literals and `any()` at the same time"
);
}
if values.is_empty() && !values_any_specified && !any_specified {
values.insert(None);
} else if !values.is_empty() && values_any_specified {
error!(
"`values()` arguments cannot specify string literals and `any()` at the same time"
);
}

if any_specified {
if names.is_empty()
&& values.is_empty()
&& !values_specified
&& !values_any_specified
{
check_cfg.exhaustive_names = false;
} else {
error!("`cfg(any())` can only be provided in isolation");
}
if any_specified {
if names.is_empty() && values.is_empty() && !values_specified && !values_any_specified {
check_cfg.exhaustive_names = false;
} else {
for name in names {
check_cfg
.expecteds
.entry(name.name)
.and_modify(|v| match v {
ExpectedValues::Some(v) if !values_any_specified => {
v.extend(values.clone())
}
ExpectedValues::Some(_) => *v = ExpectedValues::Any,
ExpectedValues::Any => {}
})
.or_insert_with(|| {
if values_any_specified {
ExpectedValues::Any
} else {
ExpectedValues::Some(values.clone())
}
});
}
error!("`cfg(any())` can only be provided in isolation");
}
} else {
expected_error();
for name in names {
check_cfg
.expecteds
.entry(name.name)
.and_modify(|v| match v {
ExpectedValues::Some(v) if !values_any_specified => {
v.extend(values.clone())
}
ExpectedValues::Some(_) => *v = ExpectedValues::Any,
ExpectedValues::Any => {}
})
.or_insert_with(|| {
if values_any_specified {
ExpectedValues::Any
} else {
ExpectedValues::Some(values.clone())
}
});
}
}
}

Expand Down
67 changes: 0 additions & 67 deletions src/doc/unstable-book/src/compiler-flags/check-cfg.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,70 +190,3 @@ fn shoot_lasers() {}
// the cfg(feature) list
fn write_shakespeare() {}
```

## The deprecated `names(...)` form

The `names(...)` form enables checking the names. This form uses a named list:

```bash
rustc --check-cfg 'names(name1, name2, ... nameN)'
```

where each `name` is a bare identifier (has no quotes). The order of the names is not significant.

If `--check-cfg names(...)` is specified at least once, then `rustc` will check all references to
condition names. `rustc` will check every `#[cfg]` attribute, `#[cfg_attr]` attribute, `cfg` clause
inside `#[link]` attribute and `cfg!(...)` call against the provided list of expected condition
names. If a name is not present in this list, then `rustc` will report an `unexpected_cfgs` lint
diagnostic. The default diagnostic level for this lint is `Warn`.

If `--check-cfg names(...)` is not specified, then `rustc` will not check references to condition
names.

`--check-cfg names(...)` may be specified more than once. The result is that the list of valid
condition names is merged across all options. It is legal for a condition name to be specified
more than once; redundantly specifying a condition name has no effect.

To enable checking condition names with an empty set of valid condition names, use the following
form. The parentheses are required.

```bash
rustc --check-cfg 'names()'
```

Note that `--check-cfg 'names()'` is _not_ equivalent to omitting the option entirely.
The first form enables checking condition names, while specifying that there are no valid
condition names (outside of the set of well-known names defined by `rustc`). Omitting the
`--check-cfg 'names(...)'` option does not enable checking condition names.

## The deprecated `values(...)` form

The `values(...)` form enables checking the values within list-valued conditions. It has this
form:

```bash
rustc --check-cfg `values(name, "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 `target_os`.
When the `values(...)` 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`.
To enable checking of values, but to provide an empty set of valid values, use this form:
```bash
rustc --check-cfg `values(name)`
```
The `--check-cfg values(...)` 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.
If `values()` is specified, then `rustc` will enable the checking of well-known values defined
by itself. Note that it's necessary to specify the `values()` form to enable the checking of
well known values, specifying the other forms doesn't implicitly enable it.
8 changes: 4 additions & 4 deletions tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
warning: unexpected `cfg` condition name: `unknown_key`
--> $DIR/exhaustive-names-values.rs:11:7
--> $DIR/exhaustive-names-values.rs:10:7
|
LL | #[cfg(unknown_key = "value")]
| ^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -8,7 +8,7 @@ LL | #[cfg(unknown_key = "value")]
= note: `#[warn(unexpected_cfgs)]` on by default

warning: unexpected `cfg` condition value: `value`
--> $DIR/exhaustive-names-values.rs:15:7
--> $DIR/exhaustive-names-values.rs:14:7
|
LL | #[cfg(test = "value")]
| ^^^^----------
Expand All @@ -18,13 +18,13 @@ LL | #[cfg(test = "value")]
= note: no expected value for `test`

warning: unexpected `cfg` condition name: `feature`
--> $DIR/exhaustive-names-values.rs:19:7
--> $DIR/exhaustive-names-values.rs:18:7
|
LL | #[cfg(feature = "unk")]
| ^^^^^^^^^^^^^^^

warning: unexpected `cfg` condition name: `feature`
--> $DIR/exhaustive-names-values.rs:26:7
--> $DIR/exhaustive-names-values.rs:25:7
|
LL | #[cfg(feature = "std")]
| ^^^^^^^^^^^^^^^
Expand Down
Loading

0 comments on commit 3f0369e

Please sign in to comment.