Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 40 additions & 3 deletions compiler/rustc_lint/src/early/diagnostics/check_cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,9 +316,27 @@ pub(super) fn unexpected_cfg_value(
let is_from_cargo = rustc_session::utils::was_invoked_from_cargo();
let is_from_external_macro = name_span.in_external_macro(sess.source_map());

// Show the full list if all possible values for a given name, but don't do it
// for names as the possibilities could be very long
let code_sugg = if !possibilities.is_empty() {
let code_sugg = if let Some((value, _)) = value
&& sess.psess.check_config.well_known_names.contains(&name)
&& let valid_names = possible_well_known_names_for_cfg_value(sess, value)
&& !valid_names.is_empty()
{
// Suggest changing the name to something for which `value` is an expected value.
let max_suggestions = 3;
let suggestions = valid_names
.iter()
.take(max_suggestions)
.copied()
.map(|name| lints::unexpected_cfg_value::ChangeNameSuggestion {
span: name_span,
name,
value,
})
.collect::<Vec<_>>();
lints::unexpected_cfg_value::CodeSuggestion::ChangeName { suggestions }
} else if !possibilities.is_empty() {
// Show the full list if all possible values for a given name, but don't do it
// for names as the possibilities could be very long
let expected_values = {
let (possibilities, and_more) = sort_and_truncate_possibilities(
sess,
Expand Down Expand Up @@ -419,3 +437,22 @@ pub(super) fn unexpected_cfg_value(
value: value.map_or_else(String::new, |(v, _span)| v.to_string()),
}
}

/// Ordering of the output is not stable, use this only in diagnostic code.
fn possible_well_known_names_for_cfg_value(sess: &Session, value: Symbol) -> Vec<Symbol> {
#[allow(rustc::potential_query_instability)]
sess.psess
.check_config
.well_known_names
.iter()
.filter(|name| {
sess.psess
.check_config
.expecteds
.get(*name)
.map(|expected_values| expected_values.contains(&Some(value)))
.unwrap_or_default()
})
.copied()
.collect()
}
18 changes: 18 additions & 0 deletions compiler/rustc_lint/src/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2904,6 +2904,10 @@ pub(crate) mod unexpected_cfg_value {

name: Symbol,
},
ChangeName {
#[subdiagnostic]
suggestions: Vec<ChangeNameSuggestion>,
},
}

#[derive(Subdiagnostic)]
Expand Down Expand Up @@ -2961,6 +2965,20 @@ pub(crate) mod unexpected_cfg_value {
pub and_more: usize,
}

#[derive(Subdiagnostic)]
#[suggestion(
"`{$value}` is an expected value for `{$name}`",
code = "{name}",
applicability = "maybe-incorrect",
style = "verbose"
)]
pub(crate) struct ChangeNameSuggestion {
#[primary_span]
pub span: Span,
pub name: Symbol,
pub value: Symbol,
}

#[derive(Subdiagnostic)]
pub(crate) enum InvocationHelp {
#[note(
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_session/src/config/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ impl<T: Eq + Hash> ExpectedValues<T> {
ExpectedValues::Any => false,
}
}

pub fn contains(&self, value: &Option<T>) -> bool {
match self {
ExpectedValues::Some(expecteds) => expecteds.contains(value),
ExpectedValues::Any => false,
}
}
}

impl<T: Eq + Hash> Extend<T> for ExpectedValues<T> {
Expand Down
39 changes: 39 additions & 0 deletions tests/ui/cfg/suggest-alternative-name-on-target.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#![deny(unexpected_cfgs)]
//~^ NOTE lint level is defined here

// target arch used in `target_abi`
#[cfg(target_abi = "arm")]
//~^ ERROR unexpected `cfg` condition value:
//~| NOTE see <https://doc.rust-lang.org
//~| HELP `arm` is an expected value for `target_arch`
struct A;

// target env used in `target_arch`
#[cfg(target_arch = "gnu")]
//~^ ERROR unexpected `cfg` condition value:
//~| NOTE see <https://doc.rust-lang.org
//~| HELP `gnu` is an expected value for `target_env`
struct B;

// target os used in `target_env`
#[cfg(target_env = "openbsd")]
//~^ ERROR unexpected `cfg` condition value:
//~| NOTE see <https://doc.rust-lang.org
//~| HELP `openbsd` is an expected value for `target_os`
struct C;

// target abi used in `target_os`
#[cfg(target_os = "eabi")]
//~^ ERROR unexpected `cfg` condition value:
//~| NOTE see <https://doc.rust-lang.org
//~| HELP `eabi` is an expected value for `target_abi`
struct D;

#[cfg(target_abi = "windows")]
//~^ ERROR unexpected `cfg` condition value:
//~| NOTE see <https://doc.rust-lang.org
//~| HELP `windows` is an expected value for `target_os`
//~| HELP `windows` is an expected value for `target_family`
struct E;

fn main() {}
77 changes: 77 additions & 0 deletions tests/ui/cfg/suggest-alternative-name-on-target.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
error: unexpected `cfg` condition value: `arm`
--> $DIR/suggest-alternative-name-on-target.rs:5:7
|
LL | #[cfg(target_abi = "arm")]
| ^^^^^^^^^^^^^^^^^^
|
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
note: the lint level is defined here
--> $DIR/suggest-alternative-name-on-target.rs:1:9
|
LL | #![deny(unexpected_cfgs)]
| ^^^^^^^^^^^^^^^
help: `arm` is an expected value for `target_arch`
|
LL - #[cfg(target_abi = "arm")]
LL + #[cfg(target_arch = "arm")]
|

error: unexpected `cfg` condition value: `gnu`
--> $DIR/suggest-alternative-name-on-target.rs:12:7
|
LL | #[cfg(target_arch = "gnu")]
| ^^^^^^^^^^^^^^^^^^^
|
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
help: `gnu` is an expected value for `target_env`
|
LL - #[cfg(target_arch = "gnu")]
LL + #[cfg(target_env = "gnu")]
|

error: unexpected `cfg` condition value: `openbsd`
--> $DIR/suggest-alternative-name-on-target.rs:19:7
|
LL | #[cfg(target_env = "openbsd")]
| ^^^^^^^^^^^^^^^^^^^^^^
|
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
help: `openbsd` is an expected value for `target_os`
|
LL - #[cfg(target_env = "openbsd")]
LL + #[cfg(target_os = "openbsd")]
|

error: unexpected `cfg` condition value: `eabi`
--> $DIR/suggest-alternative-name-on-target.rs:26:7
|
LL | #[cfg(target_os = "eabi")]
| ^^^^^^^^^^^^^^^^^^
|
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
help: `eabi` is an expected value for `target_abi`
|
LL - #[cfg(target_os = "eabi")]
LL + #[cfg(target_abi = "eabi")]
|

error: unexpected `cfg` condition value: `windows`
--> $DIR/suggest-alternative-name-on-target.rs:32:7
|
LL | #[cfg(target_abi = "windows")]
| ^^^^^^^^^^^^^^^^^^^^^^
|
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
help: `windows` is an expected value for `target_os`
|
LL - #[cfg(target_abi = "windows")]
LL + #[cfg(target_os = "windows")]
|
help: `windows` is an expected value for `target_family`
|
LL - #[cfg(target_abi = "windows")]
LL + #[cfg(target_family = "windows")]
|

error: aborting due to 5 previous errors

Loading