make the lint more sophisticated
This commit is contained in:
parent
8aea4b1775
commit
a6bd7cc54e
10 changed files with 194 additions and 54 deletions
|
|
@ -3539,6 +3539,7 @@ dependencies = [
|
|||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_hir",
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ edition = "2024"
|
|||
rustc_abi = { path = "../rustc_abi" }
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
rustc_feature = { path = "../rustc_feature" }
|
||||
rustc_hir = { path = "../rustc_hir" }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use rustc_ast::token::Token;
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::{AttrStyle, NodeId, token};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_feature::{AttributeTemplate, Features};
|
||||
use rustc_hir::attrs::CfgEntry;
|
||||
use rustc_hir::{AttrPath, Target};
|
||||
|
|
@ -9,11 +10,12 @@ use rustc_parse::parser::{Parser, Recovery};
|
|||
use rustc_session::Session;
|
||||
use rustc_session::lint::BuiltinLintDiag;
|
||||
use rustc_session::lint::builtin::UNREACHABLE_CFG_SELECT_PREDICATES;
|
||||
use rustc_span::{ErrorGuaranteed, Span, sym};
|
||||
use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
|
||||
|
||||
use crate::parser::MetaItemOrLitParser;
|
||||
use crate::{AttributeParser, ParsedDescription, ShouldEmit, parse_cfg_entry};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum CfgSelectPredicate {
|
||||
Cfg(CfgEntry),
|
||||
Wildcard(Token),
|
||||
|
|
@ -126,19 +128,102 @@ pub fn parse_cfg_select(
|
|||
}
|
||||
}
|
||||
|
||||
if let Some((underscore, _, _)) = branches.wildcard
|
||||
&& features.map_or(false, |f| f.enabled(rustc_span::sym::cfg_select))
|
||||
if let Some(features) = features
|
||||
&& features.enabled(sym::cfg_select)
|
||||
{
|
||||
for (predicate, _, _) in &branches.unreachable {
|
||||
let span = predicate.span();
|
||||
p.psess.buffer_lint(
|
||||
UNREACHABLE_CFG_SELECT_PREDICATES,
|
||||
span,
|
||||
lint_node_id,
|
||||
BuiltinLintDiag::UnreachableCfg { span, wildcard_span: underscore.span },
|
||||
let it = branches
|
||||
.reachable
|
||||
.iter()
|
||||
.map(|(entry, _, _)| CfgSelectPredicate::Cfg(entry.clone()))
|
||||
.chain(branches.wildcard.as_ref().map(|(t, _, _)| CfgSelectPredicate::Wildcard(*t)))
|
||||
.chain(
|
||||
branches.unreachable.iter().map(|(entry, _, _)| CfgSelectPredicate::clone(entry)),
|
||||
);
|
||||
}
|
||||
|
||||
lint_unreachable(p, it, lint_node_id);
|
||||
}
|
||||
|
||||
Ok(branches)
|
||||
}
|
||||
|
||||
fn lint_unreachable(
|
||||
p: &mut Parser<'_>,
|
||||
predicates: impl Iterator<Item = CfgSelectPredicate>,
|
||||
lint_node_id: NodeId,
|
||||
) {
|
||||
// Symbols that have a known value.
|
||||
let mut known = FxHashMap::<Symbol, bool>::default();
|
||||
let mut wildcard_span = None;
|
||||
let mut it = predicates;
|
||||
|
||||
let branch_is_unreachable = |predicate: CfgSelectPredicate, wildcard_span| {
|
||||
let span = predicate.span();
|
||||
p.psess.buffer_lint(
|
||||
UNREACHABLE_CFG_SELECT_PREDICATES,
|
||||
span,
|
||||
lint_node_id,
|
||||
BuiltinLintDiag::UnreachableCfg { span, wildcard_span },
|
||||
);
|
||||
};
|
||||
|
||||
for predicate in &mut it {
|
||||
let CfgSelectPredicate::Cfg(ref cfg_entry) = predicate else {
|
||||
wildcard_span = Some(predicate.span());
|
||||
break;
|
||||
};
|
||||
|
||||
match cfg_entry {
|
||||
CfgEntry::Bool(true, _) => {
|
||||
wildcard_span = Some(predicate.span());
|
||||
break;
|
||||
}
|
||||
CfgEntry::Bool(false, _) => continue,
|
||||
CfgEntry::NameValue { name, value, .. } => match value {
|
||||
None => {
|
||||
// `name` will be false in all subsequent branches.
|
||||
let current = known.insert(*name, false);
|
||||
|
||||
match current {
|
||||
None => continue,
|
||||
Some(false) => {
|
||||
branch_is_unreachable(predicate, None);
|
||||
break;
|
||||
}
|
||||
Some(true) => {
|
||||
// this branch will be taken, so all subsequent branches are unreachable.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(_) => { /* for now we don't bother solving these */ }
|
||||
},
|
||||
CfgEntry::Not(inner, _) => match &**inner {
|
||||
CfgEntry::NameValue { name, value: None, .. } => {
|
||||
// `name` will be true in all subsequent branches.
|
||||
let current = known.insert(*name, true);
|
||||
|
||||
match current {
|
||||
None => continue,
|
||||
Some(true) => {
|
||||
branch_is_unreachable(predicate, None);
|
||||
break;
|
||||
}
|
||||
Some(false) => {
|
||||
// this branch will be taken, so all subsequent branches are unreachable.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => { /* for now we don't bother solving these */ }
|
||||
},
|
||||
CfgEntry::All(_, _) | CfgEntry::Any(_, _) => {
|
||||
/* for now we don't bother solving these */
|
||||
}
|
||||
CfgEntry::Version(..) => { /* don't bother solving these */ }
|
||||
}
|
||||
}
|
||||
|
||||
for predicate in it {
|
||||
branch_is_unreachable(predicate, wildcard_span)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -999,6 +999,9 @@ lint_unpredictable_fn_pointer_comparisons = function pointer comparisons do not
|
|||
lint_unqualified_local_imports = `use` of a local item without leading `self::`, `super::`, or `crate::`
|
||||
|
||||
lint_unreachable_cfg_select_predicate = unreachable configuration predicate
|
||||
.label = this configuration predicate is never reached
|
||||
|
||||
lint_unreachable_cfg_select_predicate_wildcard = unreachable configuration predicate
|
||||
.label = always matches
|
||||
.label2 = this configuration predicate is never reached
|
||||
|
||||
|
|
|
|||
|
|
@ -293,9 +293,13 @@ pub fn decorate_builtin_lint(
|
|||
}
|
||||
.decorate_lint(diag);
|
||||
}
|
||||
BuiltinLintDiag::UnreachableCfg { span, wildcard_span } => {
|
||||
lints::UnreachableCfgSelectPredicate { span, wildcard_span }.decorate_lint(diag);
|
||||
}
|
||||
BuiltinLintDiag::UnreachableCfg { span, wildcard_span } => match wildcard_span {
|
||||
Some(wildcard_span) => {
|
||||
lints::UnreachableCfgSelectPredicateWildcard { span, wildcard_span }
|
||||
.decorate_lint(diag)
|
||||
}
|
||||
None => lints::UnreachableCfgSelectPredicate { span }.decorate_lint(diag),
|
||||
},
|
||||
|
||||
BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => {
|
||||
lints::UnusedCrateDependency { extern_crate, local_crate }.decorate_lint(diag)
|
||||
|
|
|
|||
|
|
@ -3344,6 +3344,13 @@ pub(crate) struct UnknownCrateTypesSuggestion {
|
|||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unreachable_cfg_select_predicate)]
|
||||
pub(crate) struct UnreachableCfgSelectPredicate {
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unreachable_cfg_select_predicate_wildcard)]
|
||||
pub(crate) struct UnreachableCfgSelectPredicateWildcard {
|
||||
#[label(lint_label2)]
|
||||
pub span: Span,
|
||||
|
||||
|
|
|
|||
|
|
@ -750,7 +750,7 @@ pub enum BuiltinLintDiag {
|
|||
AttributeLint(AttributeLintKind),
|
||||
UnreachableCfg {
|
||||
span: Span,
|
||||
wildcard_span: Span,
|
||||
wildcard_span: Option<Span>,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
#![crate_type = "lib"]
|
||||
|
||||
cfg_select! {
|
||||
true => {}
|
||||
false => {}
|
||||
invalid_cfg1 => {}
|
||||
//~^ WARN unexpected `cfg` condition name
|
||||
_ => {}
|
||||
|
|
@ -13,6 +13,6 @@ cfg_select! {
|
|||
cfg_select! {
|
||||
invalid_cfg2 => {}
|
||||
//~^ WARN unexpected `cfg` condition name
|
||||
true => {}
|
||||
false => {}
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,40 +24,40 @@ fn arm_rhs_expr_1() -> i32 {
|
|||
|
||||
fn arm_rhs_expr_2() -> i32 {
|
||||
cfg_select! {
|
||||
true => 1,
|
||||
false => 2
|
||||
false => 2,
|
||||
true => 1
|
||||
}
|
||||
}
|
||||
|
||||
fn arm_rhs_expr_3() -> i32 {
|
||||
cfg_select! {
|
||||
true => 1,
|
||||
false => 2,
|
||||
true => { 42 }
|
||||
false => -1 as i32,
|
||||
true => 2 + 2,
|
||||
false => "",
|
||||
true => if true { 42 } else { 84 }
|
||||
false => if true { 42 } else { 84 },
|
||||
true => return 42,
|
||||
false => loop {}
|
||||
true => (1, 2),
|
||||
false => (1, 2,),
|
||||
true => todo!(),
|
||||
false => println!("hello"),
|
||||
any(true) => 1,
|
||||
any(false) => 2,
|
||||
any(true) => { 42 }
|
||||
any(false) => -1 as i32,
|
||||
any(true) => 2 + 2,
|
||||
any(false) => "",
|
||||
any(true) => if true { 42 } else { 84 }
|
||||
any(false) => if true { 42 } else { 84 },
|
||||
any(true) => return 42,
|
||||
any(false) => loop {}
|
||||
any(true) => (1, 2),
|
||||
any(false) => (1, 2,),
|
||||
any(true) => todo!(),
|
||||
any(false) => println!("hello"),
|
||||
}
|
||||
}
|
||||
|
||||
fn expand_to_statements() -> i32 {
|
||||
cfg_select! {
|
||||
true => {
|
||||
let a = 1;
|
||||
a + 1
|
||||
}
|
||||
false => {
|
||||
let b = 2;
|
||||
b + 1
|
||||
}
|
||||
true => {
|
||||
let a = 1;
|
||||
a + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ fn expand_to_pattern(x: Option<i32>) -> bool {
|
|||
}
|
||||
|
||||
cfg_select! {
|
||||
true => {
|
||||
false => {
|
||||
fn foo() {}
|
||||
}
|
||||
_ => {
|
||||
|
|
@ -89,7 +89,7 @@ struct S;
|
|||
|
||||
impl S {
|
||||
cfg_select! {
|
||||
true => {
|
||||
false => {
|
||||
fn foo() {}
|
||||
}
|
||||
_ => {
|
||||
|
|
@ -100,7 +100,7 @@ impl S {
|
|||
|
||||
trait T {
|
||||
cfg_select! {
|
||||
true => {
|
||||
false => {
|
||||
fn a();
|
||||
}
|
||||
_ => {
|
||||
|
|
@ -111,7 +111,7 @@ trait T {
|
|||
|
||||
impl T for S {
|
||||
cfg_select! {
|
||||
true => {
|
||||
false => {
|
||||
fn a() {}
|
||||
}
|
||||
_ => {
|
||||
|
|
@ -122,7 +122,7 @@ impl T for S {
|
|||
|
||||
extern "C" {
|
||||
cfg_select! {
|
||||
true => {
|
||||
false => {
|
||||
fn puts(s: *const i8) -> i32;
|
||||
}
|
||||
_ => {
|
||||
|
|
@ -137,6 +137,25 @@ cfg_select! {
|
|||
//~^ WARN unreachable configuration predicate
|
||||
}
|
||||
|
||||
cfg_select! {
|
||||
true => {}
|
||||
_ => {}
|
||||
//~^ WARN unreachable configuration predicate
|
||||
}
|
||||
|
||||
cfg_select! {
|
||||
unix => {}
|
||||
not(unix) => {}
|
||||
_ => {}
|
||||
//~^ WARN unreachable configuration predicate
|
||||
}
|
||||
|
||||
cfg_select! {
|
||||
unix => {}
|
||||
unix => {}
|
||||
//~^ WARN unreachable configuration predicate
|
||||
}
|
||||
|
||||
cfg_select! {
|
||||
//~^ ERROR none of the predicates in this `cfg_select` evaluated to true
|
||||
false => {}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error: none of the predicates in this `cfg_select` evaluated to true
|
||||
--> $DIR/cfg_select.rs:140:1
|
||||
--> $DIR/cfg_select.rs:159:1
|
||||
|
|
||||
LL | / cfg_select! {
|
||||
LL | |
|
||||
|
|
@ -8,49 +8,49 @@ LL | | }
|
|||
| |_^
|
||||
|
||||
error: none of the predicates in this `cfg_select` evaluated to true
|
||||
--> $DIR/cfg_select.rs:145:1
|
||||
--> $DIR/cfg_select.rs:164:1
|
||||
|
|
||||
LL | cfg_select! {}
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `=>`
|
||||
--> $DIR/cfg_select.rs:149:5
|
||||
--> $DIR/cfg_select.rs:168:5
|
||||
|
|
||||
LL | => {}
|
||||
| ^^
|
||||
|
||||
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression
|
||||
--> $DIR/cfg_select.rs:154:5
|
||||
--> $DIR/cfg_select.rs:173:5
|
||||
|
|
||||
LL | () => {}
|
||||
| ^^ expressions are not allowed here
|
||||
|
||||
error[E0539]: malformed `cfg_select` macro input
|
||||
--> $DIR/cfg_select.rs:159:5
|
||||
--> $DIR/cfg_select.rs:178:5
|
||||
|
|
||||
LL | "str" => {}
|
||||
| ^^^^^ expected a valid identifier here
|
||||
|
||||
error[E0539]: malformed `cfg_select` macro input
|
||||
--> $DIR/cfg_select.rs:164:5
|
||||
--> $DIR/cfg_select.rs:183:5
|
||||
|
|
||||
LL | a::b => {}
|
||||
| ^^^^ expected a valid identifier here
|
||||
|
||||
error[E0537]: invalid predicate `a`
|
||||
--> $DIR/cfg_select.rs:169:5
|
||||
--> $DIR/cfg_select.rs:188:5
|
||||
|
|
||||
LL | a() => {}
|
||||
| ^^^
|
||||
|
||||
error: expected one of `(`, `::`, `=>`, or `=`, found `+`
|
||||
--> $DIR/cfg_select.rs:174:7
|
||||
--> $DIR/cfg_select.rs:193:7
|
||||
|
|
||||
LL | a + 1 => {}
|
||||
| ^ expected one of `(`, `::`, `=>`, or `=`
|
||||
|
||||
error: expected one of `(`, `::`, `=>`, or `=`, found `!`
|
||||
--> $DIR/cfg_select.rs:180:8
|
||||
--> $DIR/cfg_select.rs:199:8
|
||||
|
|
||||
LL | cfg!() => {}
|
||||
| ^ expected one of `(`, `::`, `=>`, or `=`
|
||||
|
|
@ -69,8 +69,28 @@ note: the lint level is defined here
|
|||
LL | #![warn(unreachable_cfg_select_predicates)] // Unused warnings are disabled by default in UI tests.
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: unreachable configuration predicate
|
||||
--> $DIR/cfg_select.rs:142:5
|
||||
|
|
||||
LL | true => {}
|
||||
| ---- always matches
|
||||
LL | _ => {}
|
||||
| ^ this configuration predicate is never reached
|
||||
|
||||
warning: unreachable configuration predicate
|
||||
--> $DIR/cfg_select.rs:149:5
|
||||
|
|
||||
LL | _ => {}
|
||||
| ^ this configuration predicate is never reached
|
||||
|
||||
warning: unreachable configuration predicate
|
||||
--> $DIR/cfg_select.rs:155:5
|
||||
|
|
||||
LL | unix => {}
|
||||
| ^^^^ this configuration predicate is never reached
|
||||
|
||||
warning: unexpected `cfg` condition name: `a`
|
||||
--> $DIR/cfg_select.rs:174:5
|
||||
--> $DIR/cfg_select.rs:193:5
|
||||
|
|
||||
LL | a + 1 => {}
|
||||
| ^ help: found config with similar value: `target_feature = "a"`
|
||||
|
|
@ -81,7 +101,7 @@ LL | a + 1 => {}
|
|||
= note: `#[warn(unexpected_cfgs)]` on by default
|
||||
|
||||
warning: unexpected `cfg` condition name: `cfg`
|
||||
--> $DIR/cfg_select.rs:180:5
|
||||
--> $DIR/cfg_select.rs:199:5
|
||||
|
|
||||
LL | cfg!() => {}
|
||||
| ^^^
|
||||
|
|
@ -89,7 +109,7 @@ LL | cfg!() => {}
|
|||
= help: to expect this configuration use `--check-cfg=cfg(cfg)`
|
||||
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
|
||||
|
||||
error: aborting due to 9 previous errors; 3 warnings emitted
|
||||
error: aborting due to 9 previous errors; 6 warnings emitted
|
||||
|
||||
Some errors have detailed explanations: E0537, E0539.
|
||||
For more information about an error, try `rustc --explain E0537`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue