Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/cfg_select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use rustc_hir::attrs::CfgEntry;
use rustc_parse::exp;
use rustc_parse::parser::Parser;
use rustc_session::Session;
use rustc_session::lint::BuiltinLintDiag;
use rustc_session::lint::builtin::UNREACHABLE_CFG_SELECT_PREDICATES;
use rustc_span::{ErrorGuaranteed, Ident, Span};

use crate::parser::MetaItemOrLitParser;
Expand All @@ -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.
Expand Down Expand Up @@ -86,5 +97,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 },
);
}
}
Comment on lines +100 to +112
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem to warn, unless there is a wildcard, why so? Does it not warn in case of

cfg_select! {
    unix => true,
    not(unix) => false,
    windows => false,
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is correct, it's hard to do better than that. we'd need to actually have some sort of logic solver to do so in general, and even then I think it might misfire if there is some sort of feature flag implication that the checker does not know about.

So the current imlementation is basic but reliable.


Ok(branches)
}
4 changes: 0 additions & 4 deletions compiler/rustc_builtin_macros/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,6 @@ builtin_macros_cfg_accessible_unspecified_path = `cfg_accessible` path is not sp
builtin_macros_cfg_select_no_matches = none of the predicates in this `cfg_select` evaluated to true
builtin_macros_cfg_select_unreachable = unreachable predicate
.label = always matches
.label2 = this predicate is never reached
builtin_macros_coerce_pointee_requires_maybe_sized = `derive(CoercePointee)` requires `{$name}` to be marked `?Sized`
builtin_macros_coerce_pointee_requires_one_field = `CoercePointee` can only be derived on `struct`s with at least one field
Expand Down
18 changes: 2 additions & 16 deletions compiler/rustc_builtin_macros/src/cfg_select.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
use rustc_ast::tokenstream::TokenStream;
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, MacroExpanderResult};
use rustc_span::{Ident, Span, sym};

use crate::errors::{CfgSelectNoMatches, CfgSelectUnreachable};
use crate::errors::CfgSelectNoMatches;

/// Selects the first arm whose predicate evaluates to true.
fn select_arm(ecx: &ExtCtxt<'_>, branches: CfgSelectBranches) -> Option<(TokenStream, Span)> {
Expand All @@ -32,18 +30,6 @@ pub(super) fn expand_cfg_select<'cx>(
ecx.current_expansion.lint_node_id,
) {
Ok(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((tts, arm_span)) = select_arm(ecx, branches) {
return ExpandResult::from_tts(
ecx,
Expand Down
11 changes: 0 additions & 11 deletions compiler/rustc_builtin_macros/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1000,17 +1000,6 @@ pub(crate) struct CfgSelectNoMatches {
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(builtin_macros_cfg_select_unreachable)]
pub(crate) struct CfgSelectUnreachable {
#[primary_span]
#[label(builtin_macros_label2)]
pub span: Span,

#[label]
pub wildcard_span: Span,
}

#[derive(Diagnostic)]
#[diag(builtin_macros_eii_extern_target_expected_macro)]
pub(crate) struct EiiExternTargetExpectedMacro {
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,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 = "...")`.
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_lint/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -969,6 +969,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(...)`
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_lint/src/early/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_lint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,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,
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_lint/src/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3298,3 +3298,13 @@ pub(crate) struct DocTestUnknown {
#[derive(LintDiagnostic)]
#[diag(lint_doc_test_literal)]
pub(crate) struct DocTestLiteral;

#[derive(LintDiagnostic)]
#[diag(lint_unreachable_cfg_select_predicate)]
pub(crate) struct UnreachableCfgSelectPredicate {
#[label(lint_label2)]
pub span: Span,

#[label]
pub wildcard_span: Span,
}
29 changes: 29 additions & 0 deletions compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ declare_lint_pass! {
UNKNOWN_LINTS,
UNNAMEABLE_TEST_ITEMS,
UNNAMEABLE_TYPES,
UNREACHABLE_CFG_SELECT_PREDICATES,
UNREACHABLE_CODE,
UNREACHABLE_PATTERNS,
UNSAFE_ATTR_OUTSIDE_UNSAFE,
Expand Down Expand Up @@ -852,6 +853,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.
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_lint_defs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -748,6 +748,10 @@ pub enum BuiltinLintDiag {
},
UnusedVisibility(Span),
AttributeLint(AttributeLintKind),
UnreachableCfg {
span: Span,
wildcard_span: Span,
},
}

#[derive(Debug, HashStable_Generic)]
Expand Down
11 changes: 11 additions & 0 deletions tests/ui/feature-gates/feature-gate-cfg-select.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 25 additions & 0 deletions tests/ui/feature-gates/feature-gate-cfg-select.stderr
Original file line number Diff line number Diff line change
@@ -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`.
3 changes: 2 additions & 1 deletion tests/ui/macros/cfg_select.rs
Original file line number Diff line number Diff line change
@@ -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! {
Expand Down Expand Up @@ -50,7 +51,7 @@ fn arm_rhs_expr_3() -> i32 {
cfg_select! {
_ => {}
true => {}
//~^ WARN unreachable predicate
//~^ WARN unreachable configuration predicate
}

cfg_select! {
Expand Down
44 changes: 25 additions & 19 deletions tests/ui/macros/cfg_select.stderr
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
warning: unreachable predicate
--> $DIR/cfg_select.rs:52: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:56:1
--> $DIR/cfg_select.rs:57:1
|
LL | / cfg_select! {
LL | |
Expand All @@ -16,57 +8,71 @@ LL | | }
| |_^

error: none of the predicates in this `cfg_select` evaluated to true
--> $DIR/cfg_select.rs:61:1
--> $DIR/cfg_select.rs:62:1
|
LL | cfg_select! {}
| ^^^^^^^^^^^^^^

error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `=>`
--> $DIR/cfg_select.rs:65:5
--> $DIR/cfg_select.rs:66:5
|
LL | => {}
| ^^

error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression
--> $DIR/cfg_select.rs:70:5
--> $DIR/cfg_select.rs:71:5
|
LL | () => {}
| ^^ expressions are not allowed here

error[E0539]: malformed `cfg_select` macro input
--> $DIR/cfg_select.rs:75:5
--> $DIR/cfg_select.rs:76:5
|
LL | "str" => {}
| ^^^^^ expected a valid identifier here
|

error[E0539]: malformed `cfg_select` macro input
--> $DIR/cfg_select.rs:80:5
--> $DIR/cfg_select.rs:81:5
|
LL | a::b => {}
| ^^^^ expected a valid identifier here
|

error[E0537]: invalid predicate `a`
--> $DIR/cfg_select.rs:85:5
--> $DIR/cfg_select.rs:86:5
|
LL | a() => {}
| ^^^

error: expected one of `(`, `::`, `=>`, or `=`, found `+`
--> $DIR/cfg_select.rs:90:7
--> $DIR/cfg_select.rs:91:7
|
LL | a + 1 => {}
| ^ expected one of `(`, `::`, `=>`, or `=`

error: expected one of `(`, `::`, `=>`, or `=`, found `!`
--> $DIR/cfg_select.rs:96:8
--> $DIR/cfg_select.rs:97:8
|
LL | cfg!() => {}
| ^ expected one of `(`, `::`, `=>`, or `=`

warning: unreachable configuration predicate
--> $DIR/cfg_select.rs:53: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:90:5
--> $DIR/cfg_select.rs:91:5
|
LL | a + 1 => {}
| ^ help: found config with similar value: `target_feature = "a"`
Expand All @@ -77,7 +83,7 @@ LL | a + 1 => {}
= note: `#[warn(unexpected_cfgs)]` on by default

warning: unexpected `cfg` condition name: `cfg`
--> $DIR/cfg_select.rs:96:5
--> $DIR/cfg_select.rs:97:5
|
LL | cfg!() => {}
| ^^^
Expand Down
Loading