about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2023-10-17 19:07:21 +0200
committerGitHub <noreply@github.com>2023-10-17 19:07:21 +0200
commitce407429dd978624310ae8a1cba9ab481fb8dae3 (patch)
tree7e951f67556f7a7923cc4a2115b4fbcbc0a01c54
parent93e62a260f9edb5813a73908120a43f1415f2c8c (diff)
parentfc78d789887047e128a36bd6e8294e15e57f50a0 (diff)
downloadrust-ce407429dd978624310ae8a1cba9ab481fb8dae3.tar.gz
rust-ce407429dd978624310ae8a1cba9ab481fb8dae3.zip
Rollup merge of #111072 - Urgau:check-cfg-new-syntax, r=petrochenkov
Add new simpler and more explicit syntax for check-cfg

<details>
<summary>
Old proposition (before the MCP)
</summary>

This PR adds a new simpler and more explicit syntax for check-cfg. It consist of two new form:
 - `exhaustive(names, values)`
 - `configure(name, "value1", "value2", ... "valueN")`

The preview forms `names(...)` and `values(...)` have implicit meaning that are not strait-forward. In particular `values(foo)`&`values(bar)` and `names(foo, bar)` are not equivalent which has created [some confusions](https://github.com/rust-lang/rust/pull/98080).

Also the `names()` and `values()` form are not clear either and again created some confusions where peoples believed that `values()`&`values(foo)` could be reduced to just `values(foo)`.

To fix that the two new forms are made to be explicit and simpler. See the table of correspondence:
  - `names()` -> `exhaustive(names)`
  - `values()` -> `exhaustive(values)`
  - `names(foo)` -> `exhaustive(names)`&`configure(foo)`
  - `values(foo)` -> `configure(foo)`
  - `values(feat, "foo", "bar")` -> `configure(feat, "foo", "bar")`
  - `values(foo)`&`values(bar)` -> `configure(foo, bar)`
  - `names()`&`values()`&`values(my_cfg)` -> `exhaustive(names, values)`&`configure(my_cfg)`

Another benefits of the new syntax is that it allow for further options (like conditional checking for --cfg, currently always on) without syntax change.

The two previous forms are deprecated and will be removed once cargo and beta rustc have the necessary support.

</details>

This PR is the first part of the implementation of [MCP636 - Simplify and improve explicitness of the check-cfg syntax](https://github.com/rust-lang/compiler-team/issues/636).

## New `cfg` form

It introduces the new [`cfg` form](https://github.com/rust-lang/compiler-team/issues/636) and deprecate the other two:
```
rustc --check-cfg 'cfg(name1, ..., nameN, values("value1", "value2", ... "valueN"))'
```

## Default built-in names and values

It also changes the default for the built-in names and values checking.

 - Built-in values checking would always be activated as long as a `--check-cfg` argument is present
 - Built-in names checking would always be activated as long as a `--check-cfg` argument is present **unless** if any `cfg(any())` arg is passed

~~**Note: depends on https://github.com/rust-lang/rust/pull/111068 but is reviewable (last two commits)!**~~

Resolve https://github.com/rust-lang/compiler-team/issues/636

r? `@petrochenkov`
-rw-r--r--compiler/rustc_interface/src/interface.rs139
-rw-r--r--compiler/rustc_interface/src/lib.rs1
-rw-r--r--src/doc/rustdoc/src/unstable-features.md4
-rw-r--r--src/doc/unstable-book/src/compiler-flags/check-cfg.md216
-rw-r--r--tests/rustdoc-ui/check-cfg/check-cfg-unstable.rs2
-rw-r--r--tests/rustdoc-ui/check-cfg/check-cfg.rs2
-rw-r--r--tests/rustdoc-ui/doctest/check-cfg-test.rs2
-rw-r--r--tests/ui/check-cfg/allow-at-crate-level.rs2
-rw-r--r--tests/ui/check-cfg/allow-macro-cfg.rs2
-rw-r--r--tests/ui/check-cfg/allow-same-level.rs2
-rw-r--r--tests/ui/check-cfg/allow-top-level.rs2
-rw-r--r--tests/ui/check-cfg/allow-upper-level.rs2
-rw-r--r--tests/ui/check-cfg/compact-names.rs2
-rw-r--r--tests/ui/check-cfg/compact-values.rs2
-rw-r--r--tests/ui/check-cfg/concat-values.rs13
-rw-r--r--tests/ui/check-cfg/concat-values.stderr19
-rw-r--r--tests/ui/check-cfg/diagnotics.rs2
-rw-r--r--tests/ui/check-cfg/empty-names.rs10
-rw-r--r--tests/ui/check-cfg/empty-values.rs10
-rw-r--r--tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr25
-rw-r--r--tests/ui/check-cfg/exhaustive-names-values.empty_names_values.stderr25
-rw-r--r--tests/ui/check-cfg/exhaustive-names-values.feature.stderr33
-rw-r--r--tests/ui/check-cfg/exhaustive-names-values.full.stderr33
-rw-r--r--tests/ui/check-cfg/exhaustive-names-values.rs34
-rw-r--r--tests/ui/check-cfg/exhaustive-names.empty_names.stderr (renamed from tests/ui/check-cfg/empty-names.stderr)8
-rw-r--r--tests/ui/check-cfg/exhaustive-names.exhaustive_names.stderr15
-rw-r--r--tests/ui/check-cfg/exhaustive-names.rs12
-rw-r--r--tests/ui/check-cfg/exhaustive-values.empty_cfg.stderr17
-rw-r--r--tests/ui/check-cfg/exhaustive-values.empty_values.stderr (renamed from tests/ui/check-cfg/empty-values.stderr)2
-rw-r--r--tests/ui/check-cfg/exhaustive-values.rs13
-rw-r--r--tests/ui/check-cfg/exhaustive-values.without_names.stderr13
-rw-r--r--tests/ui/check-cfg/invalid-arguments.anything_else.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.giberich.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.ident_in_values_1.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.ident_in_values_2.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.mixed_any.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.mixed_values_any.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.multiple_any.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.multiple_values.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.multiple_values_any.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.not_empty_any.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.not_empty_values_any.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.rs32
-rw-r--r--tests/ui/check-cfg/invalid-arguments.string_for_name_1.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.string_for_name_2.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.unknown_meta_item_1.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.unknown_meta_item_2.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.unknown_meta_item_3.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.values_any_before_ident.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.values_any_missing_values.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-cfg-name.rs14
-rw-r--r--tests/ui/check-cfg/invalid-cfg-value.rs18
-rw-r--r--tests/ui/check-cfg/mix.cfg.stderr (renamed from tests/ui/check-cfg/mix.stderr)54
-rw-r--r--tests/ui/check-cfg/mix.names_values.stderr192
-rw-r--r--tests/ui/check-cfg/mix.rs6
-rw-r--r--tests/ui/check-cfg/no-expected-values.empty.stderr (renamed from tests/ui/check-cfg/no-values.stderr)4
-rw-r--r--tests/ui/check-cfg/no-expected-values.mixed.stderr23
-rw-r--r--tests/ui/check-cfg/no-expected-values.rs20
-rw-r--r--tests/ui/check-cfg/no-expected-values.simple.stderr23
-rw-r--r--tests/ui/check-cfg/no-expected-values.values.stderr23
-rw-r--r--tests/ui/check-cfg/no-values.rs14
-rw-r--r--tests/ui/check-cfg/stmt-no-ice.rs2
-rw-r--r--tests/ui/check-cfg/unexpected-cfg-name.exhaustive.stderr (renamed from tests/ui/check-cfg/invalid-cfg-name.stderr)2
-rw-r--r--tests/ui/check-cfg/unexpected-cfg-name.names.stderr10
-rw-r--r--tests/ui/check-cfg/unexpected-cfg-name.rs16
-rw-r--r--tests/ui/check-cfg/unexpected-cfg-value.cfg.stderr (renamed from tests/ui/check-cfg/invalid-cfg-value.stderr)4
-rw-r--r--tests/ui/check-cfg/unexpected-cfg-value.rs22
-rw-r--r--tests/ui/check-cfg/unexpected-cfg-value.values.stderr25
-rw-r--r--tests/ui/check-cfg/unknown-values.rs17
-rw-r--r--tests/ui/check-cfg/well-known-names.rs2
-rw-r--r--tests/ui/check-cfg/well-known-names.stderr8
-rw-r--r--tests/ui/check-cfg/well-known-values.rs2
72 files changed, 1017 insertions, 216 deletions
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 3e77a84bf9e..d2ce77ad535 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -125,8 +125,13 @@ pub fn parse_cfgspecs(
 /// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`.
 pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> CheckCfg {
     rustc_span::create_default_session_if_not_set_then(move |_| {
-        let mut check_cfg = CheckCfg::default();
+        // If any --check-cfg is passed then exhaustive_values and exhaustive_names
+        // are enabled by default.
+        let exhaustive_names = !specs.is_empty();
+        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}`"
@@ -142,18 +147,21 @@ pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> Check
                 };
             }
 
-            let expected_error = || {
-                error!(
-                    "expected `names(name1, name2, ... nameN)` or \
-                        `values(name, \"value1\", \"value2\", ... \"valueN\")`"
-                )
-            };
+            let expected_error =
+                || error!("expected `cfg(name, values(\"value1\", \"value2\", ... \"valueN\"))`");
 
             match maybe_new_parser_from_source_str(&sess, filename, s.to_string()) {
                 Ok(mut parser) => match parser.parse_meta_item() {
                     Ok(meta_item) if parser.token == token::Eof => {
                         if let Some(args) = meta_item.meta_item_list() {
                             if meta_item.has_name(sym::names) {
+                                // 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);
+
                                 check_cfg.exhaustive_names = true;
                                 for arg in args {
                                     if arg.is_word() && arg.ident().is_some() {
@@ -167,6 +175,13 @@ pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> Check
                                     }
                                 }
                             } else if meta_item.has_name(sym::values) {
+                                // 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 let Some((name, values)) = args.split_first() {
                                     if name.is_word() && name.ident().is_some() {
                                         let ident = name.ident().expect("multi-segment cfg key");
@@ -216,6 +231,116 @@ pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> Check
                                 } 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.to_string()));
+                                            } 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(...)`"
+                                        );
+                                    }
+                                }
+
+                                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_any_specified
+                                    {
+                                        error!("`cfg(any())` can only be provided in isolation");
+                                    }
+
+                                    check_cfg.exhaustive_names = false;
+                                } else {
+                                    for name in names {
+                                        check_cfg
+                                            .expecteds
+                                            .entry(name.to_string())
+                                            .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())
+                                                }
+                                            });
+                                    }
+                                }
                             } else {
                                 expected_error();
                             }
diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs
index 76131c1ad69..ffa2667a351 100644
--- a/compiler/rustc_interface/src/lib.rs
+++ b/compiler/rustc_interface/src/lib.rs
@@ -3,6 +3,7 @@
 #![feature(internal_output_capture)]
 #![feature(thread_spawn_unchecked)]
 #![feature(lazy_cell)]
+#![feature(let_chains)]
 #![feature(try_blocks)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md
index 199b5d69a1c..41602dec44c 100644
--- a/src/doc/rustdoc/src/unstable-features.md
+++ b/src/doc/rustdoc/src/unstable-features.md
@@ -628,10 +628,10 @@ Using this flag looks like this:
 
 ```bash
 $ rustdoc src/lib.rs -Z unstable-options \
-    --check-cfg='names()' --check-cfg='values(feature, "foo", "bar")'
+    --check-cfg='cfg(feature, values("foo", "bar"))'
 ```
 
-The example above check every well known names (`target_os`, `doc`, `test`, ... via `names()`)
+The example above check every well known names and values (`target_os`, `doc`, `test`, ...)
 and check the values of `feature`: `foo` and `bar`.
 
 ### `--generate-link-to-definition`: Generate links on types in source code
diff --git a/src/doc/unstable-book/src/compiler-flags/check-cfg.md b/src/doc/unstable-book/src/compiler-flags/check-cfg.md
index 10f0fbc5062..ca18ec567a4 100644
--- a/src/doc/unstable-book/src/compiler-flags/check-cfg.md
+++ b/src/doc/unstable-book/src/compiler-flags/check-cfg.md
@@ -10,97 +10,80 @@ This feature allows you to enable complete or partial checking of configuration.
 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-cfg` option can take one of two forms:
+`--check-cfg` option take one form:
 
-1. `--check-cfg names(...)` enables checking condition names.
-2. `--check-cfg values(...)` enables checking the values within list-valued conditions.
-
-These two options are independent. `names` checks only the namespace of condition names
-while `values` checks only the namespace of the values of list-valued conditions.
+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 `names(...)` and `values(...)`.
+pass all expected names and values using `cfg(...)`.
 
-## The `names(...)` form
+## The `cfg(...)` form
 
-The `names(...)` form enables checking the names. This form uses a named list:
+The `cfg(...)` form enables checking the values within list-valued conditions. It has this
+basic form:
 
 ```bash
-rustc --check-cfg 'names(name1, name2, ... nameN)'
+rustc --check-cfg 'cfg(name1, ..., nameN, values("value1", "value2", ... "valueN"))'
 ```
 
-where each `name` is a bare identifier (has no quotes). The order of the names is not significant.
+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`.
 
-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`.
+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`.
 
-If `--check-cfg names(...)` is not specified, then `rustc` will not check references to condition
-names.
+To enable checking of values, but to provide an empty set of expected values, use these forms:
 
-`--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.
+```bash
+rustc --check-cfg 'cfg(name1, ..., nameN)'
+rustc --check-cfg 'cfg(name1, ..., nameN, values())'
+```
 
-To enable checking condition names with an empty set of valid condition names, use the following
-form. The parentheses are required.
+To enable checking of name but not values (i.e. unknown expected values), use this form:
 
 ```bash
-rustc --check-cfg 'names()'
+rustc --check-cfg 'cfg(name1, ..., nameN, values(any()))'
 ```
 
-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 `values(...)` form
+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()`).
 
-The `values(...)` form enables checking the values within list-valued conditions. It has this
-form:
+## Well known names and values
 
-```bash
-rustc --check-cfg `values(name, "value1", "value2", ... "valueN")'
-```
+`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.
 
-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`.
+Well known values checking is always enabled as long as a `--check-cfg` argument is present.
 
-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`.
+Well known names checking is always enable as long as a `--check-cfg` argument is present
+**unless** any `cfg(any())` argument is passed.
 
-To enable checking of values, but to provide an empty set of valid values, use this form:
+To disable checking of well known names, use this form:
 
 ```bash
-rustc --check-cfg `values(name)`
+rustc --check-cfg 'cfg(any())'
 ```
 
-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.
+NOTE: If one want to enable values and names checking without having any cfg to declare, one
+can use an empty `cfg()` argument.
 
 ## Examples
 
 Consider this command line:
 
 ```bash
-rustc --check-cfg 'names(feature)' \
-      --check-cfg 'values(feature, "lion", "zebra")' \
+rustc --check-cfg 'cfg(feature, values("lion", "zebra"))' \
       --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. Consider compiling this code:
+feature is enabled, while the `zebra` feature is disabled. Exhaustive checking of names and
+values are enabled by default. Consider compiling this code:
 
 ```rust
 // This is expected, and tame_lion() will be compiled
@@ -119,35 +102,36 @@ fn poke_platypus() {}
 // and will cause a compiler warning (by default).
 #[cfg(feechure = "lion")]
 fn tame_lion() {}
-```
 
-> Note: The `--check-cfg names(feature)` option is necessary only to enable checking the condition
-> name, as in the last example. `feature` is a well-known (always-expected) condition name, and so
-> it is not necessary to specify it in a `--check-cfg 'names(...)'` option. That option can be
-> shortened to > `--check-cfg names()` in order to enable checking well-known condition names.
+// This is UNEXPECTED, because 'windows' is a well known condition name,
+// and because 'windows' doens't take any values,
+// and will cause a compiler warning (by default).
+#[cfg(windows = "unix")]
+fn tame_windows() {}
+```
 
 ### Example: Checking condition names, but not values
 
 ```bash
 # This turns on checking for condition names, but not values, such as 'feature' values.
-rustc --check-cfg 'names(is_embedded, has_feathers)' \
+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 names()
-fn do_embedded() {}
+#[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 names()
-fn do_features() {}
+#[cfg(has_feathers)]        // This is expected as "has_feathers" was provided in cfg()
+fn do_features() {}         // and because names exhaustiveness was not disbaled
 
-#[cfg(has_feathers = "zapping")] // This is expected as "has_feathers" was provided in names()
+#[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 names()
+                            // "has_mumble_frotz" was not provided in cfg()
 fn do_mumble_frotz() {}
 ```
 
@@ -155,25 +139,25 @@ fn do_mumble_frotz() {}
 
 ```bash
 # This turns on checking for feature values, but not for condition names.
-rustc --check-cfg 'values(feature, "zapping", "lasers")' \
+rustc --check-cfg 'configure(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 not
-                            // enable (ie not names())
+#[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, --check-cfg names(...) was never used so no name
+#[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 values(feature) list
+#[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
-                            // --check-cfg values(feature) list
+                            // cfg(feature) list
 fn write_shakespeare() {}
 ```
 
@@ -181,26 +165,92 @@ fn write_shakespeare() {}
 
 ```bash
 # This turns on checking for feature values and for condition names.
-rustc --check-cfg 'names(is_embedded, has_feathers)' \
-      --check-cfg 'values(feature, "zapping", "lasers")' \
+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 names()
-fn do_embedded() {}
+#[cfg(is_embedded)]         // This is expected because "is_embedded" was provided in cfg()
+fn do_embedded() {}         // and doesn't take any value
 
-#[cfg(has_feathers)]        // This is expected because "has_feathers" was provided in names()
-fn do_features() {}
+#[cfg(has_feathers)]        // This is expected because "has_feathers" was provided in cfg()
+fn do_features() {}         // and deosn't take any value
 
-#[cfg(has_mumble_frotz)]    // This is UNEXPECTED, because has_mumble_frotz is not in the
-                            // --check-cfg names(...) list
+#[cfg(has_mumble_frotz)]    // This is UNEXPECTED, because "has_mumble_frotz" was never provided
 fn do_mumble_frotz() {}
 
-#[cfg(feature = "lasers")]  // This is expected, "lasers" is in the values(feature) list
+#[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 values(feature) list
+                            // 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.
diff --git a/tests/rustdoc-ui/check-cfg/check-cfg-unstable.rs b/tests/rustdoc-ui/check-cfg/check-cfg-unstable.rs
index 5c500ce6ce0..806b6d1253d 100644
--- a/tests/rustdoc-ui/check-cfg/check-cfg-unstable.rs
+++ b/tests/rustdoc-ui/check-cfg/check-cfg-unstable.rs
@@ -1,2 +1,2 @@
 // check-fail
-// compile-flags: --check-cfg=names()
+// compile-flags: --check-cfg=cfg()
diff --git a/tests/rustdoc-ui/check-cfg/check-cfg.rs b/tests/rustdoc-ui/check-cfg/check-cfg.rs
index fa8789ad3ed..96fa9e08dde 100644
--- a/tests/rustdoc-ui/check-cfg/check-cfg.rs
+++ b/tests/rustdoc-ui/check-cfg/check-cfg.rs
@@ -1,5 +1,5 @@
 // check-pass
-// compile-flags: --check-cfg=names() -Z unstable-options
+// compile-flags: --check-cfg=cfg() -Z unstable-options
 
 /// uniz is nor a builtin nor pass as arguments so is unexpected
 #[cfg(uniz)]
diff --git a/tests/rustdoc-ui/doctest/check-cfg-test.rs b/tests/rustdoc-ui/doctest/check-cfg-test.rs
index 49a801c3fb3..38cd59aa790 100644
--- a/tests/rustdoc-ui/doctest/check-cfg-test.rs
+++ b/tests/rustdoc-ui/doctest/check-cfg-test.rs
@@ -1,5 +1,5 @@
 // check-pass
-// compile-flags: --test --nocapture --check-cfg=values(feature,"test") -Z unstable-options
+// compile-flags: --test --nocapture --check-cfg=cfg(feature,values("test")) -Z unstable-options
 // normalize-stderr-test: "tests/rustdoc-ui/doctest" -> "$$DIR"
 // normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR"
 // normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
diff --git a/tests/ui/check-cfg/allow-at-crate-level.rs b/tests/ui/check-cfg/allow-at-crate-level.rs
index ce3383a2961..1629d2e0b67 100644
--- a/tests/ui/check-cfg/allow-at-crate-level.rs
+++ b/tests/ui/check-cfg/allow-at-crate-level.rs
@@ -1,7 +1,7 @@
 // This test check that #![allow(unexpected_cfgs)] works with --cfg
 //
 // check-pass
-// compile-flags: --cfg=unexpected --check-cfg=names() -Z unstable-options
+// compile-flags: --cfg=unexpected --check-cfg=cfg() -Z unstable-options
 
 #![allow(unexpected_cfgs)]
 
diff --git a/tests/ui/check-cfg/allow-macro-cfg.rs b/tests/ui/check-cfg/allow-macro-cfg.rs
index 8016a4d190c..ea26355aca8 100644
--- a/tests/ui/check-cfg/allow-macro-cfg.rs
+++ b/tests/ui/check-cfg/allow-macro-cfg.rs
@@ -1,7 +1,7 @@
 // This test check that local #[allow(unexpected_cfgs)] works
 //
 // check-pass
-// compile-flags:--check-cfg=names() -Z unstable-options
+// compile-flags: --check-cfg=cfg() -Z unstable-options
 
 #[allow(unexpected_cfgs)]
 fn foo() {
diff --git a/tests/ui/check-cfg/allow-same-level.rs b/tests/ui/check-cfg/allow-same-level.rs
index 6c869dc4202..29491e0b39e 100644
--- a/tests/ui/check-cfg/allow-same-level.rs
+++ b/tests/ui/check-cfg/allow-same-level.rs
@@ -1,7 +1,7 @@
 // This test check that #[allow(unexpected_cfgs)] doesn't work if put on the same level
 //
 // check-pass
-// compile-flags:--check-cfg=names() -Z unstable-options
+// compile-flags: --check-cfg=cfg() -Z unstable-options
 
 #[allow(unexpected_cfgs)]
 #[cfg(FALSE)]
diff --git a/tests/ui/check-cfg/allow-top-level.rs b/tests/ui/check-cfg/allow-top-level.rs
index d14b0eae5cc..df06f655d9a 100644
--- a/tests/ui/check-cfg/allow-top-level.rs
+++ b/tests/ui/check-cfg/allow-top-level.rs
@@ -1,7 +1,7 @@
 // This test check that a top-level #![allow(unexpected_cfgs)] works
 //
 // check-pass
-// compile-flags:--check-cfg=names() -Z unstable-options
+// compile-flags: --check-cfg=cfg() -Z unstable-options
 
 #![allow(unexpected_cfgs)]
 
diff --git a/tests/ui/check-cfg/allow-upper-level.rs b/tests/ui/check-cfg/allow-upper-level.rs
index 04340694d9c..bd5c97815f2 100644
--- a/tests/ui/check-cfg/allow-upper-level.rs
+++ b/tests/ui/check-cfg/allow-upper-level.rs
@@ -1,7 +1,7 @@
 // This test check that #[allow(unexpected_cfgs)] work if put on an upper level
 //
 // check-pass
-// compile-flags:--check-cfg=names() -Z unstable-options
+// compile-flags: --check-cfg=cfg() -Z unstable-options
 
 #[allow(unexpected_cfgs)]
 mod aa {
diff --git a/tests/ui/check-cfg/compact-names.rs b/tests/ui/check-cfg/compact-names.rs
index bff80740039..4f7168255cf 100644
--- a/tests/ui/check-cfg/compact-names.rs
+++ b/tests/ui/check-cfg/compact-names.rs
@@ -1,7 +1,7 @@
 // This test check that we correctly emit an warning for compact cfg
 //
 // check-pass
-// compile-flags:--check-cfg=names() -Z unstable-options
+// compile-flags: --check-cfg=cfg() -Z unstable-options
 
 #![feature(cfg_target_compact)]
 
diff --git a/tests/ui/check-cfg/compact-values.rs b/tests/ui/check-cfg/compact-values.rs
index 1f17057840c..13c072fe920 100644
--- a/tests/ui/check-cfg/compact-values.rs
+++ b/tests/ui/check-cfg/compact-values.rs
@@ -1,7 +1,7 @@
 // This test check that we correctly emit an warning for compact cfg
 //
 // check-pass
-// compile-flags:--check-cfg=values() -Z unstable-options
+// compile-flags: --check-cfg=cfg() -Z unstable-options
 
 #![feature(cfg_target_compact)]
 
diff --git a/tests/ui/check-cfg/concat-values.rs b/tests/ui/check-cfg/concat-values.rs
new file mode 100644
index 00000000000..0f9178ce6a5
--- /dev/null
+++ b/tests/ui/check-cfg/concat-values.rs
@@ -0,0 +1,13 @@
+// check-pass
+// compile-flags: -Z unstable-options
+// compile-flags: --check-cfg=cfg(my_cfg,values("foo")) --check-cfg=cfg(my_cfg,values("bar"))
+
+#[cfg(my_cfg)]
+//~^ WARNING unexpected `cfg` condition value
+fn my_cfg() {}
+
+#[cfg(my_cfg = "unk")]
+//~^ WARNING unexpected `cfg` condition value
+fn my_cfg() {}
+
+fn main() {}
diff --git a/tests/ui/check-cfg/concat-values.stderr b/tests/ui/check-cfg/concat-values.stderr
new file mode 100644
index 00000000000..da2bd7d6ad9
--- /dev/null
+++ b/tests/ui/check-cfg/concat-values.stderr
@@ -0,0 +1,19 @@
+warning: unexpected `cfg` condition value: (none)
+  --> $DIR/concat-values.rs:5:7
+   |
+LL | #[cfg(my_cfg)]
+   |       ^^^^^^
+   |
+   = note: expected values for `my_cfg` are: `bar`, `foo`
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: unexpected `cfg` condition value: `unk`
+  --> $DIR/concat-values.rs:9:7
+   |
+LL | #[cfg(my_cfg = "unk")]
+   |       ^^^^^^^^^^^^^^
+   |
+   = note: expected values for `my_cfg` are: `bar`, `foo`
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/check-cfg/diagnotics.rs b/tests/ui/check-cfg/diagnotics.rs
index 49e127d079a..45875bddc17 100644
--- a/tests/ui/check-cfg/diagnotics.rs
+++ b/tests/ui/check-cfg/diagnotics.rs
@@ -1,5 +1,5 @@
 // check-pass
-// compile-flags: --check-cfg=names() --check-cfg=values(feature,"foo") --check-cfg=values(no_values) -Z unstable-options
+// compile-flags: --check-cfg=cfg(feature,values("foo")) --check-cfg=cfg(no_values) -Z unstable-options
 
 #[cfg(featur)]
 //~^ WARNING unexpected `cfg` condition name
diff --git a/tests/ui/check-cfg/empty-names.rs b/tests/ui/check-cfg/empty-names.rs
deleted file mode 100644
index 046ff0364e2..00000000000
--- a/tests/ui/check-cfg/empty-names.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-// Check warning for unexpected cfg
-//
-// check-pass
-// compile-flags: --check-cfg=names() -Z unstable-options
-
-#[cfg(unknown_key = "value")]
-//~^ WARNING unexpected `cfg` condition name
-pub fn f() {}
-
-fn main() {}
diff --git a/tests/ui/check-cfg/empty-values.rs b/tests/ui/check-cfg/empty-values.rs
deleted file mode 100644
index 9bda42e5d15..00000000000
--- a/tests/ui/check-cfg/empty-values.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-// Check warning for unexpected cfg value
-//
-// check-pass
-// compile-flags: --check-cfg=values() -Z unstable-options
-
-#[cfg(test = "value")]
-//~^ WARNING unexpected `cfg` condition value
-pub fn f() {}
-
-fn main() {}
diff --git a/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr b/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr
new file mode 100644
index 00000000000..53ccc0f4d31
--- /dev/null
+++ b/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr
@@ -0,0 +1,25 @@
+warning: unexpected `cfg` condition name: `unknown_key`
+  --> $DIR/exhaustive-names-values.rs:12:7
+   |
+LL | #[cfg(unknown_key = "value")]
+   |       ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `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: `#[warn(unexpected_cfgs)]` on by default
+
+warning: unexpected `cfg` condition value: `value`
+  --> $DIR/exhaustive-names-values.rs:16:7
+   |
+LL | #[cfg(test = "value")]
+   |       ^^^^----------
+   |           |
+   |           help: remove the value
+   |
+   = note: no expected value for `test`
+
+warning: unexpected `empty_cfg` as condition name
+   |
+   = help: was set with `--cfg` but isn't in the `--check-cfg` expected names
+
+warning: 3 warnings emitted
+
diff --git a/tests/ui/check-cfg/exhaustive-names-values.empty_names_values.stderr b/tests/ui/check-cfg/exhaustive-names-values.empty_names_values.stderr
new file mode 100644
index 00000000000..5e8b74054ce
--- /dev/null
+++ b/tests/ui/check-cfg/exhaustive-names-values.empty_names_values.stderr
@@ -0,0 +1,25 @@
+warning: unexpected `cfg` condition name: `unknown_key`
+  --> $DIR/exhaustive-names-values.rs:12:7
+   |
+LL | #[cfg(unknown_key = "value")]
+   |       ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `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: `#[warn(unexpected_cfgs)]` on by default
+
+warning: unexpected `cfg` condition value: `value`
+  --> $DIR/exhaustive-names-values.rs:16:7
+   |
+LL | #[cfg(test = "value")]
+   |       ^^^^----------
+   |           |
+   |           help: remove the value
+   |
+   = note: no expected value for `test`
+
+warning: unexpected `empty_names_values` as condition name
+   |
+   = help: was set with `--cfg` but isn't in the `--check-cfg` expected names
+
+warning: 3 warnings emitted
+
diff --git a/tests/ui/check-cfg/exhaustive-names-values.feature.stderr b/tests/ui/check-cfg/exhaustive-names-values.feature.stderr
new file mode 100644
index 00000000000..7705a665eb7
--- /dev/null
+++ b/tests/ui/check-cfg/exhaustive-names-values.feature.stderr
@@ -0,0 +1,33 @@
+warning: unexpected `cfg` condition name: `unknown_key`
+  --> $DIR/exhaustive-names-values.rs:12:7
+   |
+LL | #[cfg(unknown_key = "value")]
+   |       ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `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: `#[warn(unexpected_cfgs)]` on by default
+
+warning: unexpected `cfg` condition value: `value`
+  --> $DIR/exhaustive-names-values.rs:16:7
+   |
+LL | #[cfg(test = "value")]
+   |       ^^^^----------
+   |           |
+   |           help: remove the value
+   |
+   = note: no expected value for `test`
+
+warning: unexpected `cfg` condition value: `unk`
+  --> $DIR/exhaustive-names-values.rs:20:7
+   |
+LL | #[cfg(feature = "unk")]
+   |       ^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: `std`
+
+warning: unexpected condition value `` for condition name `feature`
+   |
+   = help: was set with `--cfg` but isn't in the `--check-cfg` expected values
+
+warning: 4 warnings emitted
+
diff --git a/tests/ui/check-cfg/exhaustive-names-values.full.stderr b/tests/ui/check-cfg/exhaustive-names-values.full.stderr
new file mode 100644
index 00000000000..f0224a2e33c
--- /dev/null
+++ b/tests/ui/check-cfg/exhaustive-names-values.full.stderr
@@ -0,0 +1,33 @@
+warning: unexpected `cfg` condition name: `unknown_key`
+  --> $DIR/exhaustive-names-values.rs:12:7
+   |
+LL | #[cfg(unknown_key = "value")]
+   |       ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `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: `#[warn(unexpected_cfgs)]` on by default
+
+warning: unexpected `cfg` condition value: `value`
+  --> $DIR/exhaustive-names-values.rs:16:7
+   |
+LL | #[cfg(test = "value")]
+   |       ^^^^----------
+   |           |
+   |           help: remove the value
+   |
+   = note: no expected value for `test`
+
+warning: unexpected `cfg` condition value: `unk`
+  --> $DIR/exhaustive-names-values.rs:20:7
+   |
+LL | #[cfg(feature = "unk")]
+   |       ^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: `std`
+
+warning: unexpected `full` as condition name
+   |
+   = help: was set with `--cfg` but isn't in the `--check-cfg` expected names
+
+warning: 4 warnings emitted
+
diff --git a/tests/ui/check-cfg/exhaustive-names-values.rs b/tests/ui/check-cfg/exhaustive-names-values.rs
new file mode 100644
index 00000000000..f553d93cae2
--- /dev/null
+++ b/tests/ui/check-cfg/exhaustive-names-values.rs
@@ -0,0 +1,34 @@
+// Check warning for unexpected cfg in the code and in the CLI
+// arguments (here the revision cfg).
+//
+// check-pass
+// revisions: empty_names_values empty_cfg feature full
+// compile-flags: -Z unstable-options
+// [empty_names_values]compile-flags: --check-cfg=names() --check-cfg=values()
+// [empty_cfg]compile-flags: --check-cfg=cfg()
+// [feature]compile-flags: --check-cfg=cfg(feature,values("std"))
+// [full]compile-flags: --check-cfg=cfg(feature,values("std")) --check-cfg=cfg()
+
+#[cfg(unknown_key = "value")]
+//~^ WARNING unexpected `cfg` condition name
+pub fn f() {}
+
+#[cfg(test = "value")]
+//~^ WARNING unexpected `cfg` condition value
+pub fn f() {}
+
+#[cfg(feature = "unk")]
+//[feature]~^ WARNING unexpected `cfg` condition value
+//[full]~^^ WARNING unexpected `cfg` condition value
+pub fn feat() {}
+
+#[cfg(feature = "std")]
+pub fn feat() {}
+
+#[cfg(windows)]
+pub fn win() {}
+
+#[cfg(unix)]
+pub fn unix() {}
+
+fn main() {}
diff --git a/tests/ui/check-cfg/empty-names.stderr b/tests/ui/check-cfg/exhaustive-names.empty_names.stderr
index 9bba852c6de..6190ff71464 100644
--- a/tests/ui/check-cfg/empty-names.stderr
+++ b/tests/ui/check-cfg/exhaustive-names.empty_names.stderr
@@ -1,5 +1,5 @@
 warning: unexpected `cfg` condition name: `unknown_key`
-  --> $DIR/empty-names.rs:6:7
+  --> $DIR/exhaustive-names.rs:8:7
    |
 LL | #[cfg(unknown_key = "value")]
    |       ^^^^^^^^^^^^^^^^^^^^^
@@ -7,5 +7,9 @@ LL | #[cfg(unknown_key = "value")]
    = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `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: `#[warn(unexpected_cfgs)]` on by default
 
-warning: 1 warning emitted
+warning: unexpected `empty_names` as condition name
+   |
+   = help: was set with `--cfg` but isn't in the `--check-cfg` expected names
+
+warning: 2 warnings emitted
 
diff --git a/tests/ui/check-cfg/exhaustive-names.exhaustive_names.stderr b/tests/ui/check-cfg/exhaustive-names.exhaustive_names.stderr
new file mode 100644
index 00000000000..f338434cd29
--- /dev/null
+++ b/tests/ui/check-cfg/exhaustive-names.exhaustive_names.stderr
@@ -0,0 +1,15 @@
+warning: unexpected `cfg` condition name: `unknown_key`
+  --> $DIR/exhaustive-names.rs:8:7
+   |
+LL | #[cfg(unknown_key = "value")]
+   |       ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `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: `#[warn(unexpected_cfgs)]` on by default
+
+warning: unexpected `exhaustive_names` as condition name
+   |
+   = help: was set with `--cfg` but isn't in the `--check-cfg` expected names
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/check-cfg/exhaustive-names.rs b/tests/ui/check-cfg/exhaustive-names.rs
new file mode 100644
index 00000000000..b86a7f84eb4
--- /dev/null
+++ b/tests/ui/check-cfg/exhaustive-names.rs
@@ -0,0 +1,12 @@
+// Check warning for unexpected cfg
+//
+// check-pass
+// revisions: empty_names exhaustive_names
+// [empty_names]compile-flags: --check-cfg=names() -Z unstable-options
+// [exhaustive_names]compile-flags: --check-cfg=cfg() -Z unstable-options
+
+#[cfg(unknown_key = "value")]
+//~^ WARNING unexpected `cfg` condition name
+pub fn f() {}
+
+fn main() {}
diff --git a/tests/ui/check-cfg/exhaustive-values.empty_cfg.stderr b/tests/ui/check-cfg/exhaustive-values.empty_cfg.stderr
new file mode 100644
index 00000000000..999b2702849
--- /dev/null
+++ b/tests/ui/check-cfg/exhaustive-values.empty_cfg.stderr
@@ -0,0 +1,17 @@
+warning: unexpected `cfg` condition value: `value`
+  --> $DIR/exhaustive-values.rs:9:7
+   |
+LL | #[cfg(test = "value")]
+   |       ^^^^----------
+   |           |
+   |           help: remove the value
+   |
+   = note: no expected value for `test`
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: unexpected `empty_cfg` as condition name
+   |
+   = help: was set with `--cfg` but isn't in the `--check-cfg` expected names
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/check-cfg/empty-values.stderr b/tests/ui/check-cfg/exhaustive-values.empty_values.stderr
index 932651c5bfe..77ddc35100a 100644
--- a/tests/ui/check-cfg/empty-values.stderr
+++ b/tests/ui/check-cfg/exhaustive-values.empty_values.stderr
@@ -1,5 +1,5 @@
 warning: unexpected `cfg` condition value: `value`
-  --> $DIR/empty-values.rs:6:7
+  --> $DIR/exhaustive-values.rs:9:7
    |
 LL | #[cfg(test = "value")]
    |       ^^^^----------
diff --git a/tests/ui/check-cfg/exhaustive-values.rs b/tests/ui/check-cfg/exhaustive-values.rs
new file mode 100644
index 00000000000..8a1689ba86b
--- /dev/null
+++ b/tests/ui/check-cfg/exhaustive-values.rs
@@ -0,0 +1,13 @@
+// Check warning for unexpected cfg value
+//
+// check-pass
+// revisions: empty_values empty_cfg without_names
+// [empty_values]compile-flags: --check-cfg=values() -Z unstable-options
+// [empty_cfg]compile-flags: --check-cfg=cfg() -Z unstable-options
+// [without_names]compile-flags: --check-cfg=cfg(any()) -Z unstable-options
+
+#[cfg(test = "value")]
+//~^ WARNING unexpected `cfg` condition value
+pub fn f() {}
+
+fn main() {}
diff --git a/tests/ui/check-cfg/exhaustive-values.without_names.stderr b/tests/ui/check-cfg/exhaustive-values.without_names.stderr
new file mode 100644
index 00000000000..77ddc35100a
--- /dev/null
+++ b/tests/ui/check-cfg/exhaustive-values.without_names.stderr
@@ -0,0 +1,13 @@
+warning: unexpected `cfg` condition value: `value`
+  --> $DIR/exhaustive-values.rs:9:7
+   |
+LL | #[cfg(test = "value")]
+   |       ^^^^----------
+   |           |
+   |           help: remove the value
+   |
+   = note: no expected value for `test`
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/check-cfg/invalid-arguments.anything_else.stderr b/tests/ui/check-cfg/invalid-arguments.anything_else.stderr
index 850924d993a..925664bb3fc 100644
--- a/tests/ui/check-cfg/invalid-arguments.anything_else.stderr
+++ b/tests/ui/check-cfg/invalid-arguments.anything_else.stderr
@@ -1,2 +1,2 @@
-error: invalid `--check-cfg` argument: `anything_else(...)` (expected `names(name1, name2, ... nameN)` or `values(name, "value1", "value2", ... "valueN")`)
+error: invalid `--check-cfg` argument: `anything_else(...)` (expected `cfg(name, values("value1", "value2", ... "valueN"))`)
 
diff --git a/tests/ui/check-cfg/invalid-arguments.giberich.stderr b/tests/ui/check-cfg/invalid-arguments.giberich.stderr
new file mode 100644
index 00000000000..d427033fcc2
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.giberich.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg(...)` (expected `cfg(name, values("value1", "value2", ... "valueN"))`)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.ident_in_values_1.stderr b/tests/ui/check-cfg/invalid-arguments.ident_in_values_1.stderr
new file mode 100644
index 00000000000..0dc44d9ac76
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.ident_in_values_1.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg(foo,values(bar))` (`values()` arguments must be string literals or `any()`)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.ident_in_values_2.stderr b/tests/ui/check-cfg/invalid-arguments.ident_in_values_2.stderr
new file mode 100644
index 00000000000..d0a1453e3c4
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.ident_in_values_2.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg(foo,values("bar",bar,"bar"))` (`values()` arguments must be string literals or `any()`)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.mixed_any.stderr b/tests/ui/check-cfg/invalid-arguments.mixed_any.stderr
new file mode 100644
index 00000000000..9239f8cce94
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.mixed_any.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg(any(),values(any()))` (`values()` cannot be specified before the names)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.mixed_values_any.stderr b/tests/ui/check-cfg/invalid-arguments.mixed_values_any.stderr
new file mode 100644
index 00000000000..4c406143d08
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.mixed_values_any.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg(foo,values("bar",any()))` (`values()` arguments cannot specify string literals and `any()` at the same time)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.multiple_any.stderr b/tests/ui/check-cfg/invalid-arguments.multiple_any.stderr
new file mode 100644
index 00000000000..6f1db1b13c3
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.multiple_any.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg(any(),any())` (`any()` cannot be specified multiple times)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.multiple_values.stderr b/tests/ui/check-cfg/invalid-arguments.multiple_values.stderr
new file mode 100644
index 00000000000..bce305b09c3
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.multiple_values.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg(foo,values(),values())` (`values()` cannot be specified multiple times)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.multiple_values_any.stderr b/tests/ui/check-cfg/invalid-arguments.multiple_values_any.stderr
new file mode 100644
index 00000000000..748ce231af7
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.multiple_values_any.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg(foo,values(any(),any()))` (`any()` in `values()` cannot be specified multiple times)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.not_empty_any.stderr b/tests/ui/check-cfg/invalid-arguments.not_empty_any.stderr
new file mode 100644
index 00000000000..daf38147fe5
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.not_empty_any.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg(any(foo))` (`any()` must be empty)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.not_empty_values_any.stderr b/tests/ui/check-cfg/invalid-arguments.not_empty_values_any.stderr
new file mode 100644
index 00000000000..79f83e802ca
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.not_empty_values_any.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg(foo,values(any(bar)))` (`any()` must be empty)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.rs b/tests/ui/check-cfg/invalid-arguments.rs
index 5090ce3e845..79bef89c957 100644
--- a/tests/ui/check-cfg/invalid-arguments.rs
+++ b/tests/ui/check-cfg/invalid-arguments.rs
@@ -2,9 +2,33 @@
 //
 // check-fail
 // revisions: anything_else names_simple_ident values_simple_ident values_string_literals
-// [anything_else]compile-flags: -Z unstable-options --check-cfg=anything_else(...)
-// [names_simple_ident]compile-flags: -Z unstable-options --check-cfg=names("NOT_IDENT")
-// [values_simple_ident]compile-flags: -Z unstable-options --check-cfg=values("NOT_IDENT")
-// [values_string_literals]compile-flags: -Z unstable-options --check-cfg=values(test,12)
+// revisions: string_for_name_1 string_for_name_2 multiple_any multiple_values
+// revisions: multiple_values_any not_empty_any not_empty_values_any
+// revisions: values_any_missing_values values_any_before_ident ident_in_values_1
+// revisions: ident_in_values_2 unknown_meta_item_1 unknown_meta_item_2 unknown_meta_item_3
+// revisions: mixed_values_any mixed_any giberich
+//
+// compile-flags: -Z unstable-options
+// [anything_else]compile-flags: --check-cfg=anything_else(...)
+// [names_simple_ident]compile-flags: --check-cfg=names("NOT_IDENT")
+// [values_simple_ident]compile-flags: --check-cfg=values("NOT_IDENT")
+// [values_string_literals]compile-flags: --check-cfg=values(test,12)
+// [string_for_name_1]compile-flags: --check-cfg=cfg("NOT_IDENT")
+// [string_for_name_2]compile-flags: --check-cfg=cfg(foo,"NOT_IDENT",bar)
+// [multiple_any]compile-flags: --check-cfg=cfg(any(),any())
+// [multiple_values]compile-flags: --check-cfg=cfg(foo,values(),values())
+// [multiple_values_any]compile-flags: --check-cfg=cfg(foo,values(any(),any()))
+// [not_empty_any]compile-flags: --check-cfg=cfg(any(foo))
+// [not_empty_values_any]compile-flags: --check-cfg=cfg(foo,values(any(bar)))
+// [values_any_missing_values]compile-flags: --check-cfg=cfg(foo,any())
+// [values_any_before_ident]compile-flags: --check-cfg=cfg(values(any()),foo)
+// [ident_in_values_1]compile-flags: --check-cfg=cfg(foo,values(bar))
+// [ident_in_values_2]compile-flags: --check-cfg=cfg(foo,values("bar",bar,"bar"))
+// [unknown_meta_item_1]compile-flags: --check-cfg=abc()
+// [unknown_meta_item_2]compile-flags: --check-cfg=cfg(foo,test())
+// [unknown_meta_item_3]compile-flags: --check-cfg=cfg(foo,values(test()))
+// [mixed_values_any]compile-flags: --check-cfg=cfg(foo,values("bar",any()))
+// [mixed_any]compile-flags: --check-cfg=cfg(any(),values(any()))
+// [giberich]compile-flags: --check-cfg=cfg(...)
 
 fn main() {}
diff --git a/tests/ui/check-cfg/invalid-arguments.string_for_name_1.stderr b/tests/ui/check-cfg/invalid-arguments.string_for_name_1.stderr
new file mode 100644
index 00000000000..c6f6834ffd3
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.string_for_name_1.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg("NOT_IDENT")` (`cfg()` arguments must be simple identifiers, `any()` or `values(...)`)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.string_for_name_2.stderr b/tests/ui/check-cfg/invalid-arguments.string_for_name_2.stderr
new file mode 100644
index 00000000000..ab3dc86cd1a
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.string_for_name_2.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg(foo,"NOT_IDENT",bar)` (`cfg()` arguments must be simple identifiers, `any()` or `values(...)`)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_1.stderr b/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_1.stderr
new file mode 100644
index 00000000000..c04b15ec265
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_1.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `abc()` (expected `cfg(name, values("value1", "value2", ... "valueN"))`)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_2.stderr b/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_2.stderr
new file mode 100644
index 00000000000..cee65f9887b
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_2.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg(foo,test())` (`cfg()` arguments must be simple identifiers, `any()` or `values(...)`)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_3.stderr b/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_3.stderr
new file mode 100644
index 00000000000..2441e2537b7
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_3.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg(foo,values(test()))` (`values()` arguments must be string literals or `any()`)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.values_any_before_ident.stderr b/tests/ui/check-cfg/invalid-arguments.values_any_before_ident.stderr
new file mode 100644
index 00000000000..fc93ec8fbdf
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.values_any_before_ident.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg(values(any()),foo)` (`values()` cannot be specified before the names)
+
diff --git a/tests/ui/check-cfg/invalid-arguments.values_any_missing_values.stderr b/tests/ui/check-cfg/invalid-arguments.values_any_missing_values.stderr
new file mode 100644
index 00000000000..f41672fcbdb
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.values_any_missing_values.stderr
@@ -0,0 +1,2 @@
+error: invalid `--check-cfg` argument: `cfg(foo,any())` (`cfg(any())` can only be provided in isolation)
+
diff --git a/tests/ui/check-cfg/invalid-cfg-name.rs b/tests/ui/check-cfg/invalid-cfg-name.rs
deleted file mode 100644
index 8499d3d4448..00000000000
--- a/tests/ui/check-cfg/invalid-cfg-name.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-// Check warning for invalid configuration name
-//
-// edition:2018
-// check-pass
-// compile-flags: --check-cfg=names() -Z unstable-options
-
-#[cfg(widnows)]
-//~^ WARNING unexpected `cfg` condition name
-pub fn f() {}
-
-#[cfg(windows)]
-pub fn g() {}
-
-pub fn main() {}
diff --git a/tests/ui/check-cfg/invalid-cfg-value.rs b/tests/ui/check-cfg/invalid-cfg-value.rs
deleted file mode 100644
index 9e428d367fd..00000000000
--- a/tests/ui/check-cfg/invalid-cfg-value.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-// Check warning for invalid configuration value
-//
-// edition:2018
-// check-pass
-// compile-flags: --check-cfg=values(feature,"serde","full") --cfg=feature="rand" -Z unstable-options
-
-#[cfg(feature = "sedre")]
-//~^ WARNING unexpected `cfg` condition value
-pub fn f() {}
-
-#[cfg(feature = "serde")]
-pub fn g() {}
-
-#[cfg(feature = "rand")]
-//~^ WARNING unexpected `cfg` condition value
-pub fn h() {}
-
-pub fn main() {}
diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.cfg.stderr
index 23da9f22a72..daa200440cc 100644
--- a/tests/ui/check-cfg/mix.stderr
+++ b/tests/ui/check-cfg/mix.cfg.stderr
@@ -1,5 +1,5 @@
 warning: unexpected `cfg` condition name: `widnows`
-  --> $DIR/mix.rs:11:7
+  --> $DIR/mix.rs:15:7
    |
 LL | #[cfg(widnows)]
    |       ^^^^^^^ help: there is a config with a similar name: `windows`
@@ -7,7 +7,7 @@ LL | #[cfg(widnows)]
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value: (none)
-  --> $DIR/mix.rs:15:7
+  --> $DIR/mix.rs:19:7
    |
 LL | #[cfg(feature)]
    |       ^^^^^^^- help: specify a config value: `= "foo"`
@@ -15,7 +15,7 @@ LL | #[cfg(feature)]
    = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition value: `bar`
-  --> $DIR/mix.rs:22:7
+  --> $DIR/mix.rs:26:7
    |
 LL | #[cfg(feature = "bar")]
    |       ^^^^^^^^^^^^^^^
@@ -23,7 +23,7 @@ LL | #[cfg(feature = "bar")]
    = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition value: `zebra`
-  --> $DIR/mix.rs:26:7
+  --> $DIR/mix.rs:30:7
    |
 LL | #[cfg(feature = "zebra")]
    |       ^^^^^^^^^^^^^^^^^
@@ -31,12 +31,12 @@ LL | #[cfg(feature = "zebra")]
    = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition name: `uu`
-  --> $DIR/mix.rs:30:12
+  --> $DIR/mix.rs:34:12
    |
 LL | #[cfg_attr(uu, test)]
    |            ^^
    |
-   = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `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`
+   = help: expected names are: `cfg`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `names_values`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `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`
 
 warning: unexpected condition value `bar` for condition name `feature`
    |
@@ -47,13 +47,13 @@ warning: unexpected `unknown_name` as condition name
    = help: was set with `--cfg` but isn't in the `--check-cfg` expected names
 
 warning: unexpected `cfg` condition name: `widnows`
-  --> $DIR/mix.rs:39:10
+  --> $DIR/mix.rs:43:10
    |
 LL |     cfg!(widnows);
    |          ^^^^^^^ help: there is a config with a similar name: `windows`
 
 warning: unexpected `cfg` condition value: `bar`
-  --> $DIR/mix.rs:42:10
+  --> $DIR/mix.rs:46:10
    |
 LL |     cfg!(feature = "bar");
    |          ^^^^^^^^^^^^^^^
@@ -61,7 +61,7 @@ LL |     cfg!(feature = "bar");
    = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition value: `zebra`
-  --> $DIR/mix.rs:44:10
+  --> $DIR/mix.rs:48:10
    |
 LL |     cfg!(feature = "zebra");
    |          ^^^^^^^^^^^^^^^^^
@@ -69,25 +69,25 @@ LL |     cfg!(feature = "zebra");
    = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition name: `xxx`
-  --> $DIR/mix.rs:46:10
+  --> $DIR/mix.rs:50:10
    |
 LL |     cfg!(xxx = "foo");
    |          ^^^^^^^^^^^
 
 warning: unexpected `cfg` condition name: `xxx`
-  --> $DIR/mix.rs:48:10
+  --> $DIR/mix.rs:52:10
    |
 LL |     cfg!(xxx);
    |          ^^^
 
 warning: unexpected `cfg` condition name: `xxx`
-  --> $DIR/mix.rs:50:14
+  --> $DIR/mix.rs:54:14
    |
 LL |     cfg!(any(xxx, windows));
    |              ^^^
 
 warning: unexpected `cfg` condition value: `bad`
-  --> $DIR/mix.rs:52:14
+  --> $DIR/mix.rs:56:14
    |
 LL |     cfg!(any(feature = "bad", windows));
    |              ^^^^^^^^^^^^^^^
@@ -95,43 +95,43 @@ LL |     cfg!(any(feature = "bad", windows));
    = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition name: `xxx`
-  --> $DIR/mix.rs:54:23
+  --> $DIR/mix.rs:58:23
    |
 LL |     cfg!(any(windows, xxx));
    |                       ^^^
 
 warning: unexpected `cfg` condition name: `xxx`
-  --> $DIR/mix.rs:56:20
+  --> $DIR/mix.rs:60:20
    |
 LL |     cfg!(all(unix, xxx));
    |                    ^^^
 
 warning: unexpected `cfg` condition name: `aa`
-  --> $DIR/mix.rs:58:14
+  --> $DIR/mix.rs:62:14
    |
 LL |     cfg!(all(aa, bb));
    |              ^^
 
 warning: unexpected `cfg` condition name: `bb`
-  --> $DIR/mix.rs:58:18
+  --> $DIR/mix.rs:62:18
    |
 LL |     cfg!(all(aa, bb));
    |                  ^^
 
 warning: unexpected `cfg` condition name: `aa`
-  --> $DIR/mix.rs:61:14
+  --> $DIR/mix.rs:65:14
    |
 LL |     cfg!(any(aa, bb));
    |              ^^
 
 warning: unexpected `cfg` condition name: `bb`
-  --> $DIR/mix.rs:61:18
+  --> $DIR/mix.rs:65:18
    |
 LL |     cfg!(any(aa, bb));
    |                  ^^
 
 warning: unexpected `cfg` condition value: `zebra`
-  --> $DIR/mix.rs:64:20
+  --> $DIR/mix.rs:68:20
    |
 LL |     cfg!(any(unix, feature = "zebra"));
    |                    ^^^^^^^^^^^^^^^^^
@@ -139,13 +139,13 @@ LL |     cfg!(any(unix, feature = "zebra"));
    = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition name: `xxx`
-  --> $DIR/mix.rs:66:14
+  --> $DIR/mix.rs:70:14
    |
 LL |     cfg!(any(xxx, feature = "zebra"));
    |              ^^^
 
 warning: unexpected `cfg` condition value: `zebra`
-  --> $DIR/mix.rs:66:19
+  --> $DIR/mix.rs:70:19
    |
 LL |     cfg!(any(xxx, feature = "zebra"));
    |                   ^^^^^^^^^^^^^^^^^
@@ -153,19 +153,19 @@ LL |     cfg!(any(xxx, feature = "zebra"));
    = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition name: `xxx`
-  --> $DIR/mix.rs:69:14
+  --> $DIR/mix.rs:73:14
    |
 LL |     cfg!(any(xxx, unix, xxx));
    |              ^^^
 
 warning: unexpected `cfg` condition name: `xxx`
-  --> $DIR/mix.rs:69:25
+  --> $DIR/mix.rs:73:25
    |
 LL |     cfg!(any(xxx, unix, xxx));
    |                         ^^^
 
 warning: unexpected `cfg` condition value: `zebra`
-  --> $DIR/mix.rs:72:14
+  --> $DIR/mix.rs:76:14
    |
 LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
    |              ^^^^^^^^^^^^^^^^^
@@ -173,7 +173,7 @@ LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
    = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition value: `zebra`
-  --> $DIR/mix.rs:72:33
+  --> $DIR/mix.rs:76:33
    |
 LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
    |                                 ^^^^^^^^^^^^^^^^^
@@ -181,7 +181,7 @@ LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
    = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition value: `zebra`
-  --> $DIR/mix.rs:72:52
+  --> $DIR/mix.rs:76:52
    |
 LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
    |                                                    ^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/check-cfg/mix.names_values.stderr b/tests/ui/check-cfg/mix.names_values.stderr
new file mode 100644
index 00000000000..daa200440cc
--- /dev/null
+++ b/tests/ui/check-cfg/mix.names_values.stderr
@@ -0,0 +1,192 @@
+warning: unexpected `cfg` condition name: `widnows`
+  --> $DIR/mix.rs:15:7
+   |
+LL | #[cfg(widnows)]
+   |       ^^^^^^^ help: there is a config with a similar name: `windows`
+   |
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: unexpected `cfg` condition value: (none)
+  --> $DIR/mix.rs:19:7
+   |
+LL | #[cfg(feature)]
+   |       ^^^^^^^- help: specify a config value: `= "foo"`
+   |
+   = note: expected values for `feature` are: `foo`
+
+warning: unexpected `cfg` condition value: `bar`
+  --> $DIR/mix.rs:26:7
+   |
+LL | #[cfg(feature = "bar")]
+   |       ^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: `foo`
+
+warning: unexpected `cfg` condition value: `zebra`
+  --> $DIR/mix.rs:30:7
+   |
+LL | #[cfg(feature = "zebra")]
+   |       ^^^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: `foo`
+
+warning: unexpected `cfg` condition name: `uu`
+  --> $DIR/mix.rs:34:12
+   |
+LL | #[cfg_attr(uu, test)]
+   |            ^^
+   |
+   = help: expected names are: `cfg`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `names_values`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `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`
+
+warning: unexpected condition value `bar` for condition name `feature`
+   |
+   = help: was set with `--cfg` but isn't in the `--check-cfg` expected values
+
+warning: unexpected `unknown_name` as condition name
+   |
+   = help: was set with `--cfg` but isn't in the `--check-cfg` expected names
+
+warning: unexpected `cfg` condition name: `widnows`
+  --> $DIR/mix.rs:43:10
+   |
+LL |     cfg!(widnows);
+   |          ^^^^^^^ help: there is a config with a similar name: `windows`
+
+warning: unexpected `cfg` condition value: `bar`
+  --> $DIR/mix.rs:46:10
+   |
+LL |     cfg!(feature = "bar");
+   |          ^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: `foo`
+
+warning: unexpected `cfg` condition value: `zebra`
+  --> $DIR/mix.rs:48:10
+   |
+LL |     cfg!(feature = "zebra");
+   |          ^^^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: `foo`
+
+warning: unexpected `cfg` condition name: `xxx`
+  --> $DIR/mix.rs:50:10
+   |
+LL |     cfg!(xxx = "foo");
+   |          ^^^^^^^^^^^
+
+warning: unexpected `cfg` condition name: `xxx`
+  --> $DIR/mix.rs:52:10
+   |
+LL |     cfg!(xxx);
+   |          ^^^
+
+warning: unexpected `cfg` condition name: `xxx`
+  --> $DIR/mix.rs:54:14
+   |
+LL |     cfg!(any(xxx, windows));
+   |              ^^^
+
+warning: unexpected `cfg` condition value: `bad`
+  --> $DIR/mix.rs:56:14
+   |
+LL |     cfg!(any(feature = "bad", windows));
+   |              ^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: `foo`
+
+warning: unexpected `cfg` condition name: `xxx`
+  --> $DIR/mix.rs:58:23
+   |
+LL |     cfg!(any(windows, xxx));
+   |                       ^^^
+
+warning: unexpected `cfg` condition name: `xxx`
+  --> $DIR/mix.rs:60:20
+   |
+LL |     cfg!(all(unix, xxx));
+   |                    ^^^
+
+warning: unexpected `cfg` condition name: `aa`
+  --> $DIR/mix.rs:62:14
+   |
+LL |     cfg!(all(aa, bb));
+   |              ^^
+
+warning: unexpected `cfg` condition name: `bb`
+  --> $DIR/mix.rs:62:18
+   |
+LL |     cfg!(all(aa, bb));
+   |                  ^^
+
+warning: unexpected `cfg` condition name: `aa`
+  --> $DIR/mix.rs:65:14
+   |
+LL |     cfg!(any(aa, bb));
+   |              ^^
+
+warning: unexpected `cfg` condition name: `bb`
+  --> $DIR/mix.rs:65:18
+   |
+LL |     cfg!(any(aa, bb));
+   |                  ^^
+
+warning: unexpected `cfg` condition value: `zebra`
+  --> $DIR/mix.rs:68:20
+   |
+LL |     cfg!(any(unix, feature = "zebra"));
+   |                    ^^^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: `foo`
+
+warning: unexpected `cfg` condition name: `xxx`
+  --> $DIR/mix.rs:70:14
+   |
+LL |     cfg!(any(xxx, feature = "zebra"));
+   |              ^^^
+
+warning: unexpected `cfg` condition value: `zebra`
+  --> $DIR/mix.rs:70:19
+   |
+LL |     cfg!(any(xxx, feature = "zebra"));
+   |                   ^^^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: `foo`
+
+warning: unexpected `cfg` condition name: `xxx`
+  --> $DIR/mix.rs:73:14
+   |
+LL |     cfg!(any(xxx, unix, xxx));
+   |              ^^^
+
+warning: unexpected `cfg` condition name: `xxx`
+  --> $DIR/mix.rs:73:25
+   |
+LL |     cfg!(any(xxx, unix, xxx));
+   |                         ^^^
+
+warning: unexpected `cfg` condition value: `zebra`
+  --> $DIR/mix.rs:76:14
+   |
+LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
+   |              ^^^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: `foo`
+
+warning: unexpected `cfg` condition value: `zebra`
+  --> $DIR/mix.rs:76:33
+   |
+LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
+   |                                 ^^^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: `foo`
+
+warning: unexpected `cfg` condition value: `zebra`
+  --> $DIR/mix.rs:76:52
+   |
+LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
+   |                                                    ^^^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: `foo`
+
+warning: 28 warnings emitted
+
diff --git a/tests/ui/check-cfg/mix.rs b/tests/ui/check-cfg/mix.rs
index 9adf5c46e43..d7b3b4953b7 100644
--- a/tests/ui/check-cfg/mix.rs
+++ b/tests/ui/check-cfg/mix.rs
@@ -3,7 +3,11 @@
 // we correctly lint on the `cfg!` macro and `cfg_attr` attribute.
 //
 // check-pass
-// compile-flags: --check-cfg=names() --check-cfg=values(feature,"foo") --cfg feature="bar" --cfg unknown_name -Z unstable-options
+// revisions: names_values cfg
+// compile-flags: --cfg feature="bar" --cfg unknown_name -Z unstable-options
+// compile-flags: --check-cfg=cfg(names_values,cfg)
+// [names_values]compile-flags: --check-cfg=names() --check-cfg=values(feature,"foo")
+// [cfg]compile-flags: --check-cfg=cfg(feature,values("foo"))
 
 #[cfg(windows)]
 fn do_windows_stuff() {}
diff --git a/tests/ui/check-cfg/no-values.stderr b/tests/ui/check-cfg/no-expected-values.empty.stderr
index b05a569dd01..5d261b2a5e6 100644
--- a/tests/ui/check-cfg/no-values.stderr
+++ b/tests/ui/check-cfg/no-expected-values.empty.stderr
@@ -1,5 +1,5 @@
 warning: unexpected `cfg` condition value: `foo`
-  --> $DIR/no-values.rs:6:7
+  --> $DIR/no-expected-values.rs:12:7
    |
 LL | #[cfg(feature = "foo")]
    |       ^^^^^^^--------
@@ -10,7 +10,7 @@ LL | #[cfg(feature = "foo")]
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value: `foo`
-  --> $DIR/no-values.rs:10:7
+  --> $DIR/no-expected-values.rs:16:7
    |
 LL | #[cfg(test = "foo")]
    |       ^^^^--------
diff --git a/tests/ui/check-cfg/no-expected-values.mixed.stderr b/tests/ui/check-cfg/no-expected-values.mixed.stderr
new file mode 100644
index 00000000000..5d261b2a5e6
--- /dev/null
+++ b/tests/ui/check-cfg/no-expected-values.mixed.stderr
@@ -0,0 +1,23 @@
+warning: unexpected `cfg` condition value: `foo`
+  --> $DIR/no-expected-values.rs:12:7
+   |
+LL | #[cfg(feature = "foo")]
+   |       ^^^^^^^--------
+   |              |
+   |              help: remove the value
+   |
+   = note: no expected value for `feature`
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: unexpected `cfg` condition value: `foo`
+  --> $DIR/no-expected-values.rs:16:7
+   |
+LL | #[cfg(test = "foo")]
+   |       ^^^^--------
+   |           |
+   |           help: remove the value
+   |
+   = note: no expected value for `test`
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/check-cfg/no-expected-values.rs b/tests/ui/check-cfg/no-expected-values.rs
new file mode 100644
index 00000000000..9e2a9f09aed
--- /dev/null
+++ b/tests/ui/check-cfg/no-expected-values.rs
@@ -0,0 +1,20 @@
+// Check that we detect unexpected value when none are allowed
+//
+// check-pass
+// revisions: values simple mixed empty
+// compile-flags: -Z unstable-options
+// compile-flags: --check-cfg=cfg(values,simple,mixed,empty)
+// [values]compile-flags: --check-cfg=values(test) --check-cfg=values(feature)
+// [simple]compile-flags: --check-cfg=cfg(test) --check-cfg=cfg(feature)
+// [mixed]compile-flags: --check-cfg=cfg(test,feature)
+// [empty]compile-flags: --check-cfg=cfg(test,feature,values())
+
+#[cfg(feature = "foo")]
+//~^ WARNING unexpected `cfg` condition value
+fn do_foo() {}
+
+#[cfg(test = "foo")]
+//~^ WARNING unexpected `cfg` condition value
+fn do_foo() {}
+
+fn main() {}
diff --git a/tests/ui/check-cfg/no-expected-values.simple.stderr b/tests/ui/check-cfg/no-expected-values.simple.stderr
new file mode 100644
index 00000000000..5d261b2a5e6
--- /dev/null
+++ b/tests/ui/check-cfg/no-expected-values.simple.stderr
@@ -0,0 +1,23 @@
+warning: unexpected `cfg` condition value: `foo`
+  --> $DIR/no-expected-values.rs:12:7
+   |
+LL | #[cfg(feature = "foo")]
+   |       ^^^^^^^--------
+   |              |
+   |              help: remove the value
+   |
+   = note: no expected value for `feature`
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: unexpected `cfg` condition value: `foo`
+  --> $DIR/no-expected-values.rs:16:7
+   |
+LL | #[cfg(test = "foo")]
+   |       ^^^^--------
+   |           |
+   |           help: remove the value
+   |
+   = note: no expected value for `test`
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/check-cfg/no-expected-values.values.stderr b/tests/ui/check-cfg/no-expected-values.values.stderr
new file mode 100644
index 00000000000..5d261b2a5e6
--- /dev/null
+++ b/tests/ui/check-cfg/no-expected-values.values.stderr
@@ -0,0 +1,23 @@
+warning: unexpected `cfg` condition value: `foo`
+  --> $DIR/no-expected-values.rs:12:7
+   |
+LL | #[cfg(feature = "foo")]
+   |       ^^^^^^^--------
+   |              |
+   |              help: remove the value
+   |
+   = note: no expected value for `feature`
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: unexpected `cfg` condition value: `foo`
+  --> $DIR/no-expected-values.rs:16:7
+   |
+LL | #[cfg(test = "foo")]
+   |       ^^^^--------
+   |           |
+   |           help: remove the value
+   |
+   = note: no expected value for `test`
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/check-cfg/no-values.rs b/tests/ui/check-cfg/no-values.rs
deleted file mode 100644
index 8c80f56cb5a..00000000000
--- a/tests/ui/check-cfg/no-values.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-// Check that we detect unexpected value when none are allowed
-//
-// check-pass
-// compile-flags: --check-cfg=values(test) --check-cfg=values(feature) -Z unstable-options
-
-#[cfg(feature = "foo")]
-//~^ WARNING unexpected `cfg` condition value
-fn do_foo() {}
-
-#[cfg(test = "foo")]
-//~^ WARNING unexpected `cfg` condition value
-fn do_foo() {}
-
-fn main() {}
diff --git a/tests/ui/check-cfg/stmt-no-ice.rs b/tests/ui/check-cfg/stmt-no-ice.rs
index cf76487ed46..383e830a1b2 100644
--- a/tests/ui/check-cfg/stmt-no-ice.rs
+++ b/tests/ui/check-cfg/stmt-no-ice.rs
@@ -1,7 +1,7 @@
 // This test checks that there is no ICE with this code
 //
 // check-pass
-// compile-flags:--check-cfg=names() -Z unstable-options
+// compile-flags:--check-cfg=cfg() -Z unstable-options
 
 fn main() {
     #[cfg(crossbeam_loom)]
diff --git a/tests/ui/check-cfg/invalid-cfg-name.stderr b/tests/ui/check-cfg/unexpected-cfg-name.exhaustive.stderr
index 8c3c72c9667..513f7ac7fd1 100644
--- a/tests/ui/check-cfg/invalid-cfg-name.stderr
+++ b/tests/ui/check-cfg/unexpected-cfg-name.exhaustive.stderr
@@ -1,5 +1,5 @@
 warning: unexpected `cfg` condition name: `widnows`
-  --> $DIR/invalid-cfg-name.rs:7:7
+  --> $DIR/unexpected-cfg-name.rs:9:7
    |
 LL | #[cfg(widnows)]
    |       ^^^^^^^ help: there is a config with a similar name: `windows`
diff --git a/tests/ui/check-cfg/unexpected-cfg-name.names.stderr b/tests/ui/check-cfg/unexpected-cfg-name.names.stderr
new file mode 100644
index 00000000000..513f7ac7fd1
--- /dev/null
+++ b/tests/ui/check-cfg/unexpected-cfg-name.names.stderr
@@ -0,0 +1,10 @@
+warning: unexpected `cfg` condition name: `widnows`
+  --> $DIR/unexpected-cfg-name.rs:9:7
+   |
+LL | #[cfg(widnows)]
+   |       ^^^^^^^ help: there is a config with a similar name: `windows`
+   |
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/check-cfg/unexpected-cfg-name.rs b/tests/ui/check-cfg/unexpected-cfg-name.rs
new file mode 100644
index 00000000000..15c3aa6e081
--- /dev/null
+++ b/tests/ui/check-cfg/unexpected-cfg-name.rs
@@ -0,0 +1,16 @@
+// Check warning for unexpected configuration name
+//
+// check-pass
+// revisions: names exhaustive
+// compile-flags: --check-cfg=cfg(names,exhaustive)
+// [names]compile-flags: --check-cfg=names() -Z unstable-options
+// [exhaustive]compile-flags: --check-cfg=cfg() -Z unstable-options
+
+#[cfg(widnows)]
+//~^ WARNING unexpected `cfg` condition name
+pub fn f() {}
+
+#[cfg(windows)]
+pub fn g() {}
+
+pub fn main() {}
diff --git a/tests/ui/check-cfg/invalid-cfg-value.stderr b/tests/ui/check-cfg/unexpected-cfg-value.cfg.stderr
index 947beac6ffd..2ed7f900557 100644
--- a/tests/ui/check-cfg/invalid-cfg-value.stderr
+++ b/tests/ui/check-cfg/unexpected-cfg-value.cfg.stderr
@@ -1,5 +1,5 @@
 warning: unexpected `cfg` condition value: `sedre`
-  --> $DIR/invalid-cfg-value.rs:7:7
+  --> $DIR/unexpected-cfg-value.rs:11:7
    |
 LL | #[cfg(feature = "sedre")]
    |       ^^^^^^^^^^-------
@@ -10,7 +10,7 @@ LL | #[cfg(feature = "sedre")]
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value: `rand`
-  --> $DIR/invalid-cfg-value.rs:14:7
+  --> $DIR/unexpected-cfg-value.rs:18:7
    |
 LL | #[cfg(feature = "rand")]
    |       ^^^^^^^^^^^^^^^^
diff --git a/tests/ui/check-cfg/unexpected-cfg-value.rs b/tests/ui/check-cfg/unexpected-cfg-value.rs
new file mode 100644
index 00000000000..a84458071de
--- /dev/null
+++ b/tests/ui/check-cfg/unexpected-cfg-value.rs
@@ -0,0 +1,22 @@
+// Check warning for invalid configuration value in the code and
+// in the cli
+//
+// check-pass
+// revisions: values cfg
+// compile-flags: --cfg=feature="rand" -Z unstable-options
+// compile-flags: --check-cfg=cfg(values,cfg)
+// [values]compile-flags: --check-cfg=values(feature,"serde","full")
+// [cfg]compile-flags: --check-cfg=cfg(feature,values("serde","full"))
+
+#[cfg(feature = "sedre")]
+//~^ WARNING unexpected `cfg` condition value
+pub fn f() {}
+
+#[cfg(feature = "serde")]
+pub fn g() {}
+
+#[cfg(feature = "rand")]
+//~^ WARNING unexpected `cfg` condition value
+pub fn h() {}
+
+pub fn main() {}
diff --git a/tests/ui/check-cfg/unexpected-cfg-value.values.stderr b/tests/ui/check-cfg/unexpected-cfg-value.values.stderr
new file mode 100644
index 00000000000..2ed7f900557
--- /dev/null
+++ b/tests/ui/check-cfg/unexpected-cfg-value.values.stderr
@@ -0,0 +1,25 @@
+warning: unexpected `cfg` condition value: `sedre`
+  --> $DIR/unexpected-cfg-value.rs:11:7
+   |
+LL | #[cfg(feature = "sedre")]
+   |       ^^^^^^^^^^-------
+   |                 |
+   |                 help: there is a expected value with a similar name: `"serde"`
+   |
+   = note: expected values for `feature` are: `full`, `serde`
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: unexpected `cfg` condition value: `rand`
+  --> $DIR/unexpected-cfg-value.rs:18:7
+   |
+LL | #[cfg(feature = "rand")]
+   |       ^^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: `full`, `serde`
+
+warning: unexpected condition value `rand` for condition name `feature`
+   |
+   = help: was set with `--cfg` but isn't in the `--check-cfg` expected values
+
+warning: 3 warnings emitted
+
diff --git a/tests/ui/check-cfg/unknown-values.rs b/tests/ui/check-cfg/unknown-values.rs
new file mode 100644
index 00000000000..c082a2f25ac
--- /dev/null
+++ b/tests/ui/check-cfg/unknown-values.rs
@@ -0,0 +1,17 @@
+// Check that no warning is emitted for unknown cfg value
+//
+// check-pass
+// revisions: simple mixed with_values
+// compile-flags: -Z unstable-options
+// compile-flags: --check-cfg=cfg(simple,mixed,with_values)
+// [simple]compile-flags: --check-cfg=cfg(foo,values(any()))
+// [mixed]compile-flags: --check-cfg=cfg(foo) --check-cfg=cfg(foo,values(any()))
+// [with_values]compile-flags:--check-cfg=cfg(foo,values(any())) --check-cfg=cfg(foo,values("aa"))
+
+#[cfg(foo = "value")]
+pub fn f() {}
+
+#[cfg(foo)]
+pub fn f() {}
+
+fn main() {}
diff --git a/tests/ui/check-cfg/well-known-names.rs b/tests/ui/check-cfg/well-known-names.rs
index e57fb69a1e0..1dcb419b4a7 100644
--- a/tests/ui/check-cfg/well-known-names.rs
+++ b/tests/ui/check-cfg/well-known-names.rs
@@ -1,7 +1,7 @@
 // This test checks that we lint on non well known names and that we don't lint on well known names
 //
 // check-pass
-// compile-flags: --check-cfg=names() -Z unstable-options
+// compile-flags: --check-cfg=cfg() -Z unstable-options
 
 #[cfg(target_oz = "linux")]
 //~^ WARNING unexpected `cfg` condition name
diff --git a/tests/ui/check-cfg/well-known-names.stderr b/tests/ui/check-cfg/well-known-names.stderr
index a5d38a99eee..3001289b7e0 100644
--- a/tests/ui/check-cfg/well-known-names.stderr
+++ b/tests/ui/check-cfg/well-known-names.stderr
@@ -2,11 +2,13 @@ warning: unexpected `cfg` condition name: `target_oz`
   --> $DIR/well-known-names.rs:6:7
    |
 LL | #[cfg(target_oz = "linux")]
-   |       ---------^^^^^^^^^^
-   |       |
-   |       help: there is a config with a similar name: `target_os`
+   |       ^^^^^^^^^^^^^^^^^^^
    |
    = note: `#[warn(unexpected_cfgs)]` on by default
+help: there is a config with a similar name and value
+   |
+LL | #[cfg(target_os = "linux")]
+   |       ~~~~~~~~~
 
 warning: unexpected `cfg` condition name: `features`
   --> $DIR/well-known-names.rs:13:7
diff --git a/tests/ui/check-cfg/well-known-values.rs b/tests/ui/check-cfg/well-known-values.rs
index 96375dc8d31..8b56c8729d8 100644
--- a/tests/ui/check-cfg/well-known-values.rs
+++ b/tests/ui/check-cfg/well-known-values.rs
@@ -2,7 +2,7 @@
 // values
 //
 // check-pass
-// compile-flags: --check-cfg=values() -Z unstable-options
+// compile-flags: --check-cfg=cfg() -Z unstable-options
 
 #[cfg(target_os = "linuz")]
 //~^ WARNING unexpected `cfg` condition value