Skip to content

Commit 0ebe680

Browse files
committed
make the lint more sophisticated
1 parent e00d4ea commit 0ebe680

10 files changed

Lines changed: 194 additions & 54 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3539,6 +3539,7 @@ dependencies = [
35393539
"rustc_abi",
35403540
"rustc_ast",
35413541
"rustc_ast_pretty",
3542+
"rustc_data_structures",
35423543
"rustc_errors",
35433544
"rustc_feature",
35443545
"rustc_hir",

compiler/rustc_attr_parsing/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ edition = "2024"
88
rustc_abi = { path = "../rustc_abi" }
99
rustc_ast = { path = "../rustc_ast" }
1010
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
11+
rustc_data_structures = { path = "../rustc_data_structures" }
1112
rustc_errors = { path = "../rustc_errors" }
1213
rustc_feature = { path = "../rustc_feature" }
1314
rustc_hir = { path = "../rustc_hir" }

compiler/rustc_attr_parsing/src/attributes/cfg_select.rs

Lines changed: 96 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use rustc_ast::token::Token;
22
use rustc_ast::tokenstream::TokenStream;
33
use rustc_ast::{AttrStyle, NodeId, token};
4+
use rustc_data_structures::fx::FxHashMap;
45
use rustc_feature::{AttributeTemplate, Features};
56
use rustc_hir::attrs::CfgEntry;
67
use rustc_hir::{AttrPath, Target};
@@ -9,11 +10,12 @@ use rustc_parse::parser::{Parser, Recovery};
910
use rustc_session::Session;
1011
use rustc_session::lint::BuiltinLintDiag;
1112
use rustc_session::lint::builtin::UNREACHABLE_CFG_SELECT_PREDICATES;
12-
use rustc_span::{ErrorGuaranteed, Span, sym};
13+
use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
1314

1415
use crate::parser::MetaItemOrLitParser;
1516
use crate::{AttributeParser, ParsedDescription, ShouldEmit, parse_cfg_entry};
1617

18+
#[derive(Clone)]
1719
pub enum CfgSelectPredicate {
1820
Cfg(CfgEntry),
1921
Wildcard(Token),
@@ -126,19 +128,102 @@ pub fn parse_cfg_select(
126128
}
127129
}
128130

129-
if let Some((underscore, _, _)) = branches.wildcard
130-
&& features.map_or(false, |f| f.enabled(rustc_span::sym::cfg_select))
131+
if let Some(features) = features
132+
&& features.enabled(sym::cfg_select)
131133
{
132-
for (predicate, _, _) in &branches.unreachable {
133-
let span = predicate.span();
134-
p.psess.buffer_lint(
135-
UNREACHABLE_CFG_SELECT_PREDICATES,
136-
span,
137-
lint_node_id,
138-
BuiltinLintDiag::UnreachableCfg { span, wildcard_span: underscore.span },
134+
let it = branches
135+
.reachable
136+
.iter()
137+
.map(|(entry, _, _)| CfgSelectPredicate::Cfg(entry.clone()))
138+
.chain(branches.wildcard.as_ref().map(|(t, _, _)| CfgSelectPredicate::Wildcard(*t)))
139+
.chain(
140+
branches.unreachable.iter().map(|(entry, _, _)| CfgSelectPredicate::clone(entry)),
139141
);
140-
}
142+
143+
lint_unreachable(p, it, lint_node_id);
141144
}
142145

143146
Ok(branches)
144147
}
148+
149+
fn lint_unreachable(
150+
p: &mut Parser<'_>,
151+
predicates: impl Iterator<Item = CfgSelectPredicate>,
152+
lint_node_id: NodeId,
153+
) {
154+
// Symbols that have a known value.
155+
let mut known = FxHashMap::<Symbol, bool>::default();
156+
let mut wildcard_span = None;
157+
let mut it = predicates;
158+
159+
let branch_is_unreachable = |predicate: CfgSelectPredicate, wildcard_span| {
160+
let span = predicate.span();
161+
p.psess.buffer_lint(
162+
UNREACHABLE_CFG_SELECT_PREDICATES,
163+
span,
164+
lint_node_id,
165+
BuiltinLintDiag::UnreachableCfg { span, wildcard_span },
166+
);
167+
};
168+
169+
for predicate in &mut it {
170+
let CfgSelectPredicate::Cfg(ref cfg_entry) = predicate else {
171+
wildcard_span = Some(predicate.span());
172+
break;
173+
};
174+
175+
match cfg_entry {
176+
CfgEntry::Bool(true, _) => {
177+
wildcard_span = Some(predicate.span());
178+
break;
179+
}
180+
CfgEntry::Bool(false, _) => continue,
181+
CfgEntry::NameValue { name, value, .. } => match value {
182+
None => {
183+
// `name` will be false in all subsequent branches.
184+
let current = known.insert(*name, false);
185+
186+
match current {
187+
None => continue,
188+
Some(false) => {
189+
branch_is_unreachable(predicate, None);
190+
break;
191+
}
192+
Some(true) => {
193+
// this branch will be taken, so all subsequent branches are unreachable.
194+
break;
195+
}
196+
}
197+
}
198+
Some(_) => { /* for now we don't bother solving these */ }
199+
},
200+
CfgEntry::Not(inner, _) => match &**inner {
201+
CfgEntry::NameValue { name, value: None, .. } => {
202+
// `name` will be true in all subsequent branches.
203+
let current = known.insert(*name, true);
204+
205+
match current {
206+
None => continue,
207+
Some(true) => {
208+
branch_is_unreachable(predicate, None);
209+
break;
210+
}
211+
Some(false) => {
212+
// this branch will be taken, so all subsequent branches are unreachable.
213+
break;
214+
}
215+
}
216+
}
217+
_ => { /* for now we don't bother solving these */ }
218+
},
219+
CfgEntry::All(_, _) | CfgEntry::Any(_, _) => {
220+
/* for now we don't bother solving these */
221+
}
222+
CfgEntry::Version(..) => { /* don't bother solving these */ }
223+
}
224+
}
225+
226+
for predicate in it {
227+
branch_is_unreachable(predicate, wildcard_span)
228+
}
229+
}

compiler/rustc_lint/messages.ftl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -999,6 +999,9 @@ lint_unpredictable_fn_pointer_comparisons = function pointer comparisons do not
999999
lint_unqualified_local_imports = `use` of a local item without leading `self::`, `super::`, or `crate::`
10001000
10011001
lint_unreachable_cfg_select_predicate = unreachable configuration predicate
1002+
.label = this configuration predicate is never reached
1003+
1004+
lint_unreachable_cfg_select_predicate_wildcard = unreachable configuration predicate
10021005
.label = always matches
10031006
.label2 = this configuration predicate is never reached
10041007

compiler/rustc_lint/src/early/diagnostics.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -293,9 +293,13 @@ pub fn decorate_builtin_lint(
293293
}
294294
.decorate_lint(diag);
295295
}
296-
BuiltinLintDiag::UnreachableCfg { span, wildcard_span } => {
297-
lints::UnreachableCfgSelectPredicate { span, wildcard_span }.decorate_lint(diag);
298-
}
296+
BuiltinLintDiag::UnreachableCfg { span, wildcard_span } => match wildcard_span {
297+
Some(wildcard_span) => {
298+
lints::UnreachableCfgSelectPredicateWildcard { span, wildcard_span }
299+
.decorate_lint(diag)
300+
}
301+
None => lints::UnreachableCfgSelectPredicate { span }.decorate_lint(diag),
302+
},
299303

300304
BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => {
301305
lints::UnusedCrateDependency { extern_crate, local_crate }.decorate_lint(diag)

compiler/rustc_lint/src/lints.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3344,6 +3344,13 @@ pub(crate) struct UnknownCrateTypesSuggestion {
33443344
#[derive(LintDiagnostic)]
33453345
#[diag(lint_unreachable_cfg_select_predicate)]
33463346
pub(crate) struct UnreachableCfgSelectPredicate {
3347+
#[label]
3348+
pub span: Span,
3349+
}
3350+
3351+
#[derive(LintDiagnostic)]
3352+
#[diag(lint_unreachable_cfg_select_predicate_wildcard)]
3353+
pub(crate) struct UnreachableCfgSelectPredicateWildcard {
33473354
#[label(lint_label2)]
33483355
pub span: Span,
33493356

compiler/rustc_lint_defs/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -750,7 +750,7 @@ pub enum BuiltinLintDiag {
750750
AttributeLint(AttributeLintKind),
751751
UnreachableCfg {
752752
span: Span,
753-
wildcard_span: Span,
753+
wildcard_span: Option<Span>,
754754
},
755755
}
756756

tests/ui/check-cfg/cfg-select.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#![crate_type = "lib"]
55

66
cfg_select! {
7-
true => {}
7+
false => {}
88
invalid_cfg1 => {}
99
//~^ WARN unexpected `cfg` condition name
1010
_ => {}
@@ -13,6 +13,6 @@ cfg_select! {
1313
cfg_select! {
1414
invalid_cfg2 => {}
1515
//~^ WARN unexpected `cfg` condition name
16-
true => {}
16+
false => {}
1717
_ => {}
1818
}

tests/ui/macros/cfg_select.rs

Lines changed: 44 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -24,40 +24,40 @@ fn arm_rhs_expr_1() -> i32 {
2424

2525
fn arm_rhs_expr_2() -> i32 {
2626
cfg_select! {
27-
true => 1,
28-
false => 2
27+
false => 2,
28+
true => 1
2929
}
3030
}
3131

3232
fn arm_rhs_expr_3() -> i32 {
3333
cfg_select! {
34-
true => 1,
35-
false => 2,
36-
true => { 42 }
37-
false => -1 as i32,
38-
true => 2 + 2,
39-
false => "",
40-
true => if true { 42 } else { 84 }
41-
false => if true { 42 } else { 84 },
42-
true => return 42,
43-
false => loop {}
44-
true => (1, 2),
45-
false => (1, 2,),
46-
true => todo!(),
47-
false => println!("hello"),
34+
any(true) => 1,
35+
any(false) => 2,
36+
any(true) => { 42 }
37+
any(false) => -1 as i32,
38+
any(true) => 2 + 2,
39+
any(false) => "",
40+
any(true) => if true { 42 } else { 84 }
41+
any(false) => if true { 42 } else { 84 },
42+
any(true) => return 42,
43+
any(false) => loop {}
44+
any(true) => (1, 2),
45+
any(false) => (1, 2,),
46+
any(true) => todo!(),
47+
any(false) => println!("hello"),
4848
}
4949
}
5050

5151
fn expand_to_statements() -> i32 {
5252
cfg_select! {
53-
true => {
54-
let a = 1;
55-
a + 1
56-
}
5753
false => {
5854
let b = 2;
5955
b + 1
6056
}
57+
true => {
58+
let a = 1;
59+
a + 1
60+
}
6161
}
6262
}
6363

@@ -77,7 +77,7 @@ fn expand_to_pattern(x: Option<i32>) -> bool {
7777
}
7878

7979
cfg_select! {
80-
true => {
80+
false => {
8181
fn foo() {}
8282
}
8383
_ => {
@@ -89,7 +89,7 @@ struct S;
8989

9090
impl S {
9191
cfg_select! {
92-
true => {
92+
false => {
9393
fn foo() {}
9494
}
9595
_ => {
@@ -100,7 +100,7 @@ impl S {
100100

101101
trait T {
102102
cfg_select! {
103-
true => {
103+
false => {
104104
fn a();
105105
}
106106
_ => {
@@ -111,7 +111,7 @@ trait T {
111111

112112
impl T for S {
113113
cfg_select! {
114-
true => {
114+
false => {
115115
fn a() {}
116116
}
117117
_ => {
@@ -122,7 +122,7 @@ impl T for S {
122122

123123
extern "C" {
124124
cfg_select! {
125-
true => {
125+
false => {
126126
fn puts(s: *const i8) -> i32;
127127
}
128128
_ => {
@@ -137,6 +137,25 @@ cfg_select! {
137137
//~^ WARN unreachable configuration predicate
138138
}
139139

140+
cfg_select! {
141+
true => {}
142+
_ => {}
143+
//~^ WARN unreachable configuration predicate
144+
}
145+
146+
cfg_select! {
147+
unix => {}
148+
not(unix) => {}
149+
_ => {}
150+
//~^ WARN unreachable configuration predicate
151+
}
152+
153+
cfg_select! {
154+
unix => {}
155+
unix => {}
156+
//~^ WARN unreachable configuration predicate
157+
}
158+
140159
cfg_select! {
141160
//~^ ERROR none of the predicates in this `cfg_select` evaluated to true
142161
false => {}

0 commit comments

Comments
 (0)