Skip to content

Commit 20f27e5

Browse files
committed
add unreachable_cfg_select_predicates lint
This is emitted on branches of a `cfg_select!` that are statically known to be unreachable.
1 parent 08de25c commit 20f27e5

File tree

16 files changed

+167
-51
lines changed

16 files changed

+167
-51
lines changed

compiler/rustc_attr_parsing/src/attributes/cfg_select.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ use rustc_hir::attrs::CfgEntry;
77
use rustc_parse::exp;
88
use rustc_parse::parser::Parser;
99
use rustc_session::Session;
10+
use rustc_session::lint::BuiltinLintDiag;
11+
use rustc_session::lint::builtin::UNREACHABLE_CFG_SELECT_PREDICATES;
1012
use rustc_span::{ErrorGuaranteed, Ident, Span};
1113

1214
use crate::parser::MetaItemOrLitParser;
@@ -17,6 +19,15 @@ pub enum CfgSelectPredicate {
1719
Wildcard(Token),
1820
}
1921

22+
impl CfgSelectPredicate {
23+
fn span(&self) -> Span {
24+
match self {
25+
CfgSelectPredicate::Cfg(cfg_entry) => cfg_entry.span(),
26+
CfgSelectPredicate::Wildcard(token) => token.span,
27+
}
28+
}
29+
}
30+
2031
#[derive(Default)]
2132
pub struct CfgSelectBranches {
2233
/// All the conditional branches.
@@ -86,5 +97,19 @@ pub fn parse_cfg_select(
8697
}
8798
}
8899

100+
if let Some((underscore, _, _)) = branches.wildcard
101+
&& features.map_or(false, |f| f.enabled(rustc_span::sym::cfg_select))
102+
{
103+
for (predicate, _, _) in &branches.unreachable {
104+
let span = predicate.span();
105+
p.psess.buffer_lint(
106+
UNREACHABLE_CFG_SELECT_PREDICATES,
107+
span,
108+
lint_node_id,
109+
BuiltinLintDiag::UnreachableCfg { span, wildcard_span: underscore.span },
110+
);
111+
}
112+
}
113+
89114
Ok(branches)
90115
}

compiler/rustc_builtin_macros/messages.ftl

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,6 @@ builtin_macros_cfg_accessible_unspecified_path = `cfg_accessible` path is not sp
8686
8787
builtin_macros_cfg_select_no_matches = none of the predicates in this `cfg_select` evaluated to true
8888
89-
builtin_macros_cfg_select_unreachable = unreachable predicate
90-
.label = always matches
91-
.label2 = this predicate is never reached
92-
9389
builtin_macros_coerce_pointee_requires_maybe_sized = `derive(CoercePointee)` requires `{$name}` to be marked `?Sized`
9490
9591
builtin_macros_coerce_pointee_requires_one_field = `CoercePointee` can only be derived on `struct`s with at least one field

compiler/rustc_builtin_macros/src/cfg_select.rs

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
use rustc_ast::tokenstream::TokenStream;
22
use rustc_attr_parsing as attr;
3-
use rustc_attr_parsing::{
4-
CfgSelectBranches, CfgSelectPredicate, EvalConfigResult, parse_cfg_select,
5-
};
3+
use rustc_attr_parsing::{CfgSelectBranches, EvalConfigResult, parse_cfg_select};
64
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
75
use rustc_span::{Ident, Span, sym};
86

9-
use crate::errors::{CfgSelectNoMatches, CfgSelectUnreachable};
7+
use crate::errors::CfgSelectNoMatches;
108

119
/// Selects the first arm whose predicate evaluates to true.
1210
fn select_arm(ecx: &ExtCtxt<'_>, branches: CfgSelectBranches) -> Option<(TokenStream, Span)> {
@@ -32,18 +30,6 @@ pub(super) fn expand_cfg_select<'cx>(
3230
ecx.current_expansion.lint_node_id,
3331
) {
3432
Ok(branches) => {
35-
if let Some((underscore, _, _)) = branches.wildcard {
36-
// Warn for every unreachable predicate. We store the fully parsed branch for rustfmt.
37-
for (predicate, _, _) in &branches.unreachable {
38-
let span = match predicate {
39-
CfgSelectPredicate::Wildcard(underscore) => underscore.span,
40-
CfgSelectPredicate::Cfg(cfg) => cfg.span(),
41-
};
42-
let err = CfgSelectUnreachable { span, wildcard_span: underscore.span };
43-
ecx.dcx().emit_warn(err);
44-
}
45-
}
46-
4733
if let Some((tts, arm_span)) = select_arm(ecx, branches) {
4834
return ExpandResult::from_tts(
4935
ecx,

compiler/rustc_builtin_macros/src/errors.rs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,17 +1000,6 @@ pub(crate) struct CfgSelectNoMatches {
10001000
pub span: Span,
10011001
}
10021002

1003-
#[derive(Diagnostic)]
1004-
#[diag(builtin_macros_cfg_select_unreachable)]
1005-
pub(crate) struct CfgSelectUnreachable {
1006-
#[primary_span]
1007-
#[label(builtin_macros_label2)]
1008-
pub span: Span,
1009-
1010-
#[label]
1011-
pub wildcard_span: Span,
1012-
}
1013-
10141003
#[derive(Diagnostic)]
10151004
#[diag(builtin_macros_eii_extern_target_expected_macro)]
10161005
pub(crate) struct EiiExternTargetExpectedMacro {

compiler/rustc_lint/messages.ftl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -969,6 +969,10 @@ lint_unpredictable_fn_pointer_comparisons = function pointer comparisons do not
969969
970970
lint_unqualified_local_imports = `use` of a local item without leading `self::`, `super::`, or `crate::`
971971
972+
lint_unreachable_cfg_select_predicate = unreachable configuration predicate
973+
.label = always matches
974+
.label2 = this configuration predicate is never reached
975+
972976
lint_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe
973977
.label = usage of unsafe attribute
974978
lint_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)`

compiler/rustc_lint/src/early/diagnostics.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,10 @@ 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+
}
299+
296300
BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => {
297301
lints::UnusedCrateDependency { extern_crate, local_crate }.decorate_lint(diag)
298302
}

compiler/rustc_lint/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ fn register_builtins(store: &mut LintStore) {
296296
UNUSED_ASSIGNMENTS,
297297
DEAD_CODE,
298298
UNUSED_MUT,
299+
UNREACHABLE_CFG_SELECT_PREDICATES,
299300
UNREACHABLE_CODE,
300301
UNREACHABLE_PATTERNS,
301302
UNUSED_MUST_USE,

compiler/rustc_lint/src/lints.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3298,3 +3298,13 @@ pub(crate) struct DocTestUnknown {
32983298
#[derive(LintDiagnostic)]
32993299
#[diag(lint_doc_test_literal)]
33003300
pub(crate) struct DocTestLiteral;
3301+
3302+
#[derive(LintDiagnostic)]
3303+
#[diag(lint_unreachable_cfg_select_predicate)]
3304+
pub(crate) struct UnreachableCfgSelectPredicate {
3305+
#[label(lint_label2)]
3306+
pub span: Span,
3307+
3308+
#[label]
3309+
pub wildcard_span: Span,
3310+
}

compiler/rustc_lint_defs/src/builtin.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ declare_lint_pass! {
120120
UNKNOWN_LINTS,
121121
UNNAMEABLE_TEST_ITEMS,
122122
UNNAMEABLE_TYPES,
123+
UNREACHABLE_CFG_SELECT_PREDICATES,
123124
UNREACHABLE_CODE,
124125
UNREACHABLE_PATTERNS,
125126
UNSAFE_ATTR_OUTSIDE_UNSAFE,
@@ -852,6 +853,33 @@ declare_lint! {
852853
"detects unreachable patterns"
853854
}
854855

856+
declare_lint! {
857+
/// The `unreachable_cfg_select_predicates` lint detects unreachable configuration
858+
/// predicates in the `cfg_select!` macro.
859+
///
860+
/// ### Example
861+
///
862+
/// ```rust
863+
/// #![feature(cfg_select)]
864+
/// cfg_select! {
865+
/// _ => (),
866+
/// windows => (),
867+
/// }
868+
/// ```
869+
///
870+
/// {{produces}}
871+
///
872+
/// ### Explanation
873+
///
874+
/// This usually indicates a mistake in how the predicates are specified or
875+
/// ordered. In this example, the `_` predicate will always match, so the
876+
/// `windows` is impossible to reach. Remember, arms match in order, you
877+
/// probably wanted to put the `windows` case above the `_` case.
878+
pub UNREACHABLE_CFG_SELECT_PREDICATES,
879+
Warn,
880+
"detects unreachable configuration predicates in the cfg_select macro"
881+
}
882+
855883
declare_lint! {
856884
/// The `overlapping_range_endpoints` lint detects `match` arms that have [range patterns] that
857885
/// overlap on their endpoints.

compiler/rustc_lint_defs/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,10 @@ pub enum BuiltinLintDiag {
748748
},
749749
UnusedVisibility(Span),
750750
AttributeLint(AttributeLintKind),
751+
UnreachableCfg {
752+
span: Span,
753+
wildcard_span: Span,
754+
},
751755
}
752756

753757
#[derive(Debug, HashStable_Generic)]

0 commit comments

Comments
 (0)