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 },
);
}
}

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
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
1 change: 1 addition & 0 deletions compiler/rustc_lint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ fn register_builtins(store: &mut LintStore) {
UNUSED_ASSIGNMENTS,
DEAD_CODE,
UNUSED_MUT,
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,
}
28 changes: 28 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,33 @@ 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"
}

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
13 changes: 13 additions & 0 deletions tests/ui/feature-gates/cfg_select.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#![warn(unreachable_cfg_select_predicates)] // Unused warnings are disabled by default in UI tests.

// `#[feature(cfg_select)]` is a libs feature (so, not a lang feature), but it lints on unreachable
// branches, and that lint should only be emitted when the feature is enabled.

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() {}
13 changes: 13 additions & 0 deletions tests/ui/feature-gates/cfg_select.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
error[E0658]: use of unstable library feature `cfg_select`
--> $DIR/cfg_select.rs:6: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

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0658`.
Original file line number Diff line number Diff line change
Expand Up @@ -431,3 +431,21 @@ note: the lint level is defined here
LL | #![forbid(forbidden_lint_groups)]
| ^^^^^^^^^^^^^^^^^^^^^

Future breakage diagnostic:
error: warn(unused) incompatible with previous forbid
--> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:22:13
|
LL | #![forbid(unused)]
| ------ `forbid` level set here
LL | #![deny(unused)]
LL | #![warn(unused)]
| ^^^^^^ overruled by previous forbid
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
note: the lint level is defined here
--> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:17:11
|
LL | #![forbid(forbidden_lint_groups)]
| ^^^^^^^^^^^^^^^^^^^^^

18 changes: 18 additions & 0 deletions tests/ui/lint/outer-forbid.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -471,3 +471,21 @@ note: the lint level is defined here
LL | #![forbid(forbidden_lint_groups)]
| ^^^^^^^^^^^^^^^^^^^^^

Future breakage diagnostic:
error: allow(unused) incompatible with previous forbid
--> $DIR/outer-forbid.rs:25:9
|
LL | #![forbid(unused, non_snake_case)]
| ------ `forbid` level set here
...
LL | #[allow(unused)]
| ^^^^^^ overruled by previous forbid
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
note: the lint level is defined here
--> $DIR/outer-forbid.rs:18:11
|
LL | #![forbid(forbidden_lint_groups)]
| ^^^^^^^^^^^^^^^^^^^^^

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