Skip to content

Commit 41ad90e

Browse files
committed
add unreachable_cfgs lint
This is emitted on branches of a `cfg_select!` that are statically known to be unreachable.
1 parent 9a4b1e3 commit 41ad90e

File tree

12 files changed

+92
-51
lines changed

12 files changed

+92
-51
lines changed

compiler/rustc_attr_parsing/src/attributes/cfg_select.rs

Lines changed: 13 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_CFGS;
1012
use rustc_span::{ErrorGuaranteed, Ident, Span};
1113

1214
use crate::parser::MetaItemOrLitParser;
@@ -86,5 +88,16 @@ pub fn parse_cfg_select(
8688
}
8789
}
8890

91+
if let Some((underscore, _, _)) = branches.wildcard {
92+
for (_, _, span) in &branches.unreachable {
93+
p.psess.buffer_lint(
94+
UNREACHABLE_CFGS,
95+
*span,
96+
lint_node_id,
97+
BuiltinLintDiag::UnreachableCfg { span: *span, wildcard_span: underscore.span },
98+
);
99+
}
100+
}
101+
89102
Ok(branches)
90103
}

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
@@ -999,14 +999,3 @@ pub(crate) struct CfgSelectNoMatches {
999999
#[primary_span]
10001000
pub span: Span,
10011001
}
1002-
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-
}

compiler/rustc_lint/messages.ftl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -916,6 +916,10 @@ lint_unpredictable_fn_pointer_comparisons = function pointer comparisons do not
916916
917917
lint_unqualified_local_imports = `use` of a local item without leading `self::`, `super::`, or `crate::`
918918
919+
lint_unreachable_cfg = unreachable configuration predicate
920+
.label = always matches
921+
.label2 = this configuration predicate is never reached
922+
919923
lint_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe
920924
.label = usage of unsafe attribute
921925
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::UnreachableCfg { 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
@@ -295,6 +295,7 @@ fn register_builtins(store: &mut LintStore) {
295295
UNUSED_ASSIGNMENTS,
296296
DEAD_CODE,
297297
UNUSED_MUT,
298+
UNREACHABLE_CFGS,
298299
UNREACHABLE_CODE,
299300
UNREACHABLE_PATTERNS,
300301
UNUSED_MUST_USE,

compiler/rustc_lint/src/lints.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3199,3 +3199,13 @@ pub(crate) struct UnusedVisibility {
31993199
#[suggestion(style = "short", code = "", applicability = "machine-applicable")]
32003200
pub span: Span,
32013201
}
3202+
3203+
#[derive(LintDiagnostic)]
3204+
#[diag(lint_unreachable_cfg)]
3205+
pub(crate) struct UnreachableCfg {
3206+
#[label(lint_label2)]
3207+
pub span: Span,
3208+
3209+
#[label]
3210+
pub wildcard_span: Span,
3211+
}

compiler/rustc_lint_defs/src/builtin.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ declare_lint_pass! {
121121
UNKNOWN_LINTS,
122122
UNNAMEABLE_TEST_ITEMS,
123123
UNNAMEABLE_TYPES,
124+
UNREACHABLE_CFGS,
124125
UNREACHABLE_CODE,
125126
UNREACHABLE_PATTERNS,
126127
UNSAFE_ATTR_OUTSIDE_UNSAFE,
@@ -856,6 +857,32 @@ declare_lint! {
856857
"detects unreachable patterns"
857858
}
858859

860+
declare_lint! {
861+
/// The `unreachable_cfgs` lint detects unreachable configuration
862+
/// predicates.
863+
///
864+
/// ### Example
865+
///
866+
/// ```rust
867+
/// cfg_select! {
868+
/// _ => (),
869+
/// windows => (),
870+
/// }
871+
/// ```
872+
///
873+
/// {{produces}}
874+
///
875+
/// ### Explanation
876+
///
877+
/// This usually indicates a mistake in how the predicates are specified or
878+
/// ordered. In this example, the `_` predicate will always match, so the
879+
/// `windows` is impossible to reach. Remember, arms match in order, you
880+
/// probably wanted to put the `windows` case above the `_` case.
881+
pub UNREACHABLE_CFGS,
882+
Warn,
883+
"detects unreachable configuration predicates"
884+
}
885+
859886
declare_lint! {
860887
/// The `overlapping_range_endpoints` lint detects `match` arms that have [range patterns] that
861888
/// 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
@@ -696,6 +696,10 @@ pub enum BuiltinLintDiag {
696696
},
697697
UnusedVisibility(Span),
698698
AttributeLint(AttributeLintKind),
699+
UnreachableCfg {
700+
span: Span,
701+
wildcard_span: Span,
702+
},
699703
}
700704

701705
#[derive(Debug, HashStable_Generic)]

0 commit comments

Comments
 (0)