add unreachable_cfg_select_predicates lint
This is emitted on branches of a `cfg_select!` that are statically known to be unreachable.
This commit is contained in:
parent
efc9e1b50c
commit
8aea4b1775
14 changed files with 146 additions and 47 deletions
|
|
@ -7,6 +7,8 @@ use rustc_hir::{AttrPath, Target};
|
|||
use rustc_parse::exp;
|
||||
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 crate::parser::MetaItemOrLitParser;
|
||||
|
|
@ -17,6 +19,15 @@ pub enum CfgSelectPredicate {
|
|||
Wildcard(Token),
|
||||
}
|
||||
|
||||
impl CfgSelectPredicate {
|
||||
fn span(&self) -> Span {
|
||||
match self {
|
||||
CfgSelectPredicate::Cfg(cfg_entry) => cfg_entry.span(),
|
||||
CfgSelectPredicate::Wildcard(token) => token.span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct CfgSelectBranches {
|
||||
/// All the conditional branches.
|
||||
|
|
@ -115,5 +126,19 @@ pub fn parse_cfg_select(
|
|||
}
|
||||
}
|
||||
|
||||
if let Some((underscore, _, _)) = branches.wildcard
|
||||
&& features.map_or(false, |f| f.enabled(rustc_span::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 },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(branches)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::{Expr, ast};
|
||||
use rustc_attr_parsing as attr;
|
||||
use rustc_attr_parsing::{
|
||||
CfgSelectBranches, CfgSelectPredicate, EvalConfigResult, parse_cfg_select,
|
||||
};
|
||||
use rustc_attr_parsing::{CfgSelectBranches, EvalConfigResult, parse_cfg_select};
|
||||
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult};
|
||||
use rustc_span::{Ident, Span, sym};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::errors::{CfgSelectNoMatches, CfgSelectUnreachable};
|
||||
use crate::errors::CfgSelectNoMatches;
|
||||
|
||||
/// This intermediate structure is used to emit parse errors for the branches that are not chosen.
|
||||
/// The `MacResult` instance below parses all branches, emitting any errors it encounters, but only
|
||||
|
|
@ -75,18 +73,6 @@ pub(super) fn expand_cfg_select<'cx>(
|
|||
ecx.current_expansion.lint_node_id,
|
||||
) {
|
||||
Ok(mut branches) => {
|
||||
if let Some((underscore, _, _)) = branches.wildcard {
|
||||
// Warn for every unreachable predicate. We store the fully parsed branch for rustfmt.
|
||||
for (predicate, _, _) in &branches.unreachable {
|
||||
let span = match predicate {
|
||||
CfgSelectPredicate::Wildcard(underscore) => underscore.span,
|
||||
CfgSelectPredicate::Cfg(cfg) => cfg.span(),
|
||||
};
|
||||
let err = CfgSelectUnreachable { span, wildcard_span: underscore.span };
|
||||
ecx.dcx().emit_warn(err);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((selected_tts, selected_span)) = branches.pop_first_match(|cfg| {
|
||||
matches!(attr::eval_config_entry(&ecx.sess, cfg), EvalConfigResult::True)
|
||||
}) {
|
||||
|
|
|
|||
|
|
@ -1086,17 +1086,6 @@ pub(crate) struct CfgSelectNoMatches {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("unreachable predicate")]
|
||||
pub(crate) struct CfgSelectUnreachable {
|
||||
#[primary_span]
|
||||
#[label("this predicate is never reached")]
|
||||
pub span: Span,
|
||||
|
||||
#[label("always matches")]
|
||||
pub wildcard_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`#[eii_declaration(...)]` is only valid on macros")]
|
||||
pub(crate) struct EiiExternTargetExpectedMacro {
|
||||
|
|
|
|||
|
|
@ -392,6 +392,8 @@ declare_features! (
|
|||
(unstable, cfg_sanitize, "1.41.0", Some(39699)),
|
||||
/// Allows `cfg(sanitizer_cfi_generalize_pointers)` and `cfg(sanitizer_cfi_normalize_integers)`.
|
||||
(unstable, cfg_sanitizer_cfi, "1.77.0", Some(89653)),
|
||||
/// Provides a native way to easily manage multiple conditional flags without having to rewrite each clause multiple times.
|
||||
(unstable, cfg_select, "CURRENT_RUSTC_VERSION", Some(115585)),
|
||||
/// Allows `cfg(target(abi = "..."))`.
|
||||
(unstable, cfg_target_compact, "1.63.0", Some(96901)),
|
||||
/// Allows `cfg(target_has_atomic_load_store = "...")`.
|
||||
|
|
|
|||
|
|
@ -998,6 +998,10 @@ 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 = always matches
|
||||
.label2 = this configuration predicate is never reached
|
||||
|
||||
lint_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe
|
||||
.label = usage of unsafe attribute
|
||||
lint_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)`
|
||||
|
|
|
|||
|
|
@ -293,6 +293,10 @@ pub fn decorate_builtin_lint(
|
|||
}
|
||||
.decorate_lint(diag);
|
||||
}
|
||||
BuiltinLintDiag::UnreachableCfg { span, wildcard_span } => {
|
||||
lints::UnreachableCfgSelectPredicate { span, wildcard_span }.decorate_lint(diag);
|
||||
}
|
||||
|
||||
BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => {
|
||||
lints::UnusedCrateDependency { extern_crate, local_crate }.decorate_lint(diag)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -297,6 +297,9 @@ fn register_builtins(store: &mut LintStore) {
|
|||
UNUSED_ASSIGNMENTS,
|
||||
DEAD_CODE,
|
||||
UNUSED_MUT,
|
||||
// FIXME: add this lint when it becomes stable,
|
||||
// see https://github.com/rust-lang/rust/issues/115585.
|
||||
// UNREACHABLE_CFG_SELECT_PREDICATES,
|
||||
UNREACHABLE_CODE,
|
||||
UNREACHABLE_PATTERNS,
|
||||
UNUSED_MUST_USE,
|
||||
|
|
|
|||
|
|
@ -3340,3 +3340,13 @@ pub(crate) struct UnknownCrateTypesSuggestion {
|
|||
pub span: Span,
|
||||
pub snippet: Symbol,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unreachable_cfg_select_predicate)]
|
||||
pub(crate) struct UnreachableCfgSelectPredicate {
|
||||
#[label(lint_label2)]
|
||||
pub span: Span,
|
||||
|
||||
#[label]
|
||||
pub wildcard_span: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,6 +123,7 @@ declare_lint_pass! {
|
|||
UNKNOWN_LINTS,
|
||||
UNNAMEABLE_TEST_ITEMS,
|
||||
UNNAMEABLE_TYPES,
|
||||
UNREACHABLE_CFG_SELECT_PREDICATES,
|
||||
UNREACHABLE_CODE,
|
||||
UNREACHABLE_PATTERNS,
|
||||
UNSAFE_ATTR_OUTSIDE_UNSAFE,
|
||||
|
|
@ -855,6 +856,34 @@ declare_lint! {
|
|||
"detects unreachable patterns"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `unreachable_cfg_select_predicates` lint detects unreachable configuration
|
||||
/// predicates in the `cfg_select!` macro.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(cfg_select)]
|
||||
/// cfg_select! {
|
||||
/// _ => (),
|
||||
/// windows => (),
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// This usually indicates a mistake in how the predicates are specified or
|
||||
/// ordered. In this example, the `_` predicate will always match, so the
|
||||
/// `windows` is impossible to reach. Remember, arms match in order, you
|
||||
/// probably wanted to put the `windows` case above the `_` case.
|
||||
pub UNREACHABLE_CFG_SELECT_PREDICATES,
|
||||
Warn,
|
||||
"detects unreachable configuration predicates in the cfg_select macro",
|
||||
@feature_gate = cfg_select;
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `overlapping_range_endpoints` lint detects `match` arms that have [range patterns] that
|
||||
/// overlap on their endpoints.
|
||||
|
|
|
|||
|
|
@ -748,6 +748,10 @@ pub enum BuiltinLintDiag {
|
|||
},
|
||||
UnusedVisibility(Span),
|
||||
AttributeLint(AttributeLintKind),
|
||||
UnreachableCfg {
|
||||
span: Span,
|
||||
wildcard_span: Span,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, HashStable_Generic)]
|
||||
|
|
|
|||
11
tests/ui/feature-gates/feature-gate-cfg-select.rs
Normal file
11
tests/ui/feature-gates/feature-gate-cfg-select.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#![warn(unreachable_cfg_select_predicates)]
|
||||
//~^ WARN unknown lint: `unreachable_cfg_select_predicates`
|
||||
|
||||
cfg_select! {
|
||||
//~^ ERROR use of unstable library feature `cfg_select`
|
||||
_ => {}
|
||||
// With the feature enabled, this branch would trip the unreachable_cfg_select_predicate lint.
|
||||
true => {}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
25
tests/ui/feature-gates/feature-gate-cfg-select.stderr
Normal file
25
tests/ui/feature-gates/feature-gate-cfg-select.stderr
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
error[E0658]: use of unstable library feature `cfg_select`
|
||||
--> $DIR/feature-gate-cfg-select.rs:4:1
|
||||
|
|
||||
LL | cfg_select! {
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #115585 <https://github.com/rust-lang/rust/issues/115585> for more information
|
||||
= help: add `#![feature(cfg_select)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
warning: unknown lint: `unreachable_cfg_select_predicates`
|
||||
--> $DIR/feature-gate-cfg-select.rs:1:9
|
||||
|
|
||||
LL | #![warn(unreachable_cfg_select_predicates)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: the `unreachable_cfg_select_predicates` lint is unstable
|
||||
= note: see issue #115585 <https://github.com/rust-lang/rust/issues/115585> for more information
|
||||
= help: add `#![feature(cfg_select)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
= note: `#[warn(unknown_lints)]` on by default
|
||||
|
||||
error: aborting due to 1 previous error; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
#![feature(cfg_select)]
|
||||
#![crate_type = "lib"]
|
||||
#![warn(unreachable_cfg_select_predicates)] // Unused warnings are disabled by default in UI tests.
|
||||
|
||||
fn print() {
|
||||
println!(cfg_select! {
|
||||
|
|
@ -133,7 +134,7 @@ extern "C" {
|
|||
cfg_select! {
|
||||
_ => {}
|
||||
true => {}
|
||||
//~^ WARN unreachable predicate
|
||||
//~^ WARN unreachable configuration predicate
|
||||
}
|
||||
|
||||
cfg_select! {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,5 @@
|
|||
warning: unreachable predicate
|
||||
--> $DIR/cfg_select.rs:135:5
|
||||
|
|
||||
LL | _ => {}
|
||||
| - always matches
|
||||
LL | true => {}
|
||||
| ^^^^ this predicate is never reached
|
||||
|
||||
error: none of the predicates in this `cfg_select` evaluated to true
|
||||
--> $DIR/cfg_select.rs:139:1
|
||||
--> $DIR/cfg_select.rs:140:1
|
||||
|
|
||||
LL | / cfg_select! {
|
||||
LL | |
|
||||
|
|
@ -16,55 +8,69 @@ LL | | }
|
|||
| |_^
|
||||
|
||||
error: none of the predicates in this `cfg_select` evaluated to true
|
||||
--> $DIR/cfg_select.rs:144:1
|
||||
--> $DIR/cfg_select.rs:145:1
|
||||
|
|
||||
LL | cfg_select! {}
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `=>`
|
||||
--> $DIR/cfg_select.rs:148:5
|
||||
--> $DIR/cfg_select.rs:149:5
|
||||
|
|
||||
LL | => {}
|
||||
| ^^
|
||||
|
||||
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression
|
||||
--> $DIR/cfg_select.rs:153:5
|
||||
--> $DIR/cfg_select.rs:154:5
|
||||
|
|
||||
LL | () => {}
|
||||
| ^^ expressions are not allowed here
|
||||
|
||||
error[E0539]: malformed `cfg_select` macro input
|
||||
--> $DIR/cfg_select.rs:158:5
|
||||
--> $DIR/cfg_select.rs:159:5
|
||||
|
|
||||
LL | "str" => {}
|
||||
| ^^^^^ expected a valid identifier here
|
||||
|
||||
error[E0539]: malformed `cfg_select` macro input
|
||||
--> $DIR/cfg_select.rs:163:5
|
||||
--> $DIR/cfg_select.rs:164:5
|
||||
|
|
||||
LL | a::b => {}
|
||||
| ^^^^ expected a valid identifier here
|
||||
|
||||
error[E0537]: invalid predicate `a`
|
||||
--> $DIR/cfg_select.rs:168:5
|
||||
--> $DIR/cfg_select.rs:169:5
|
||||
|
|
||||
LL | a() => {}
|
||||
| ^^^
|
||||
|
||||
error: expected one of `(`, `::`, `=>`, or `=`, found `+`
|
||||
--> $DIR/cfg_select.rs:173:7
|
||||
--> $DIR/cfg_select.rs:174:7
|
||||
|
|
||||
LL | a + 1 => {}
|
||||
| ^ expected one of `(`, `::`, `=>`, or `=`
|
||||
|
||||
error: expected one of `(`, `::`, `=>`, or `=`, found `!`
|
||||
--> $DIR/cfg_select.rs:179:8
|
||||
--> $DIR/cfg_select.rs:180:8
|
||||
|
|
||||
LL | cfg!() => {}
|
||||
| ^ expected one of `(`, `::`, `=>`, or `=`
|
||||
|
||||
warning: unreachable configuration predicate
|
||||
--> $DIR/cfg_select.rs:136:5
|
||||
|
|
||||
LL | _ => {}
|
||||
| - always matches
|
||||
LL | true => {}
|
||||
| ^^^^ this configuration predicate is never reached
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/cfg_select.rs:3:9
|
||||
|
|
||||
LL | #![warn(unreachable_cfg_select_predicates)] // Unused warnings are disabled by default in UI tests.
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: unexpected `cfg` condition name: `a`
|
||||
--> $DIR/cfg_select.rs:173:5
|
||||
--> $DIR/cfg_select.rs:174:5
|
||||
|
|
||||
LL | a + 1 => {}
|
||||
| ^ help: found config with similar value: `target_feature = "a"`
|
||||
|
|
@ -75,7 +81,7 @@ LL | a + 1 => {}
|
|||
= note: `#[warn(unexpected_cfgs)]` on by default
|
||||
|
||||
warning: unexpected `cfg` condition name: `cfg`
|
||||
--> $DIR/cfg_select.rs:179:5
|
||||
--> $DIR/cfg_select.rs:180:5
|
||||
|
|
||||
LL | cfg!() => {}
|
||||
| ^^^
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue