Auto merge of #152294 - JonathanBrouwer:rollup-ygNTxe8, r=JonathanBrouwer

Rollup of 3 pull requests

Successful merges:

 - rust-lang/rust#149960 (add `unreachable_cfg_select_predicates` lint)
 - rust-lang/rust#152168 (Port `rustc_intrinsic_const_stable_indirect` and `rustc_intrinsic` to the new attribute parser)
 - rust-lang/rust#152289 (Also duplicate `#[expect]` attribute in `#[derive]`-ed code)
This commit is contained in:
bors
2026-02-07 15:20:28 +00:00
32 changed files with 443 additions and 90 deletions
+1
View File
@@ -3539,6 +3539,7 @@ dependencies = [
"rustc_abi",
"rustc_ast",
"rustc_ast_pretty",
"rustc_data_structures",
"rustc_errors",
"rustc_feature",
"rustc_hir",
+1 -1
View File
@@ -1397,7 +1397,7 @@ fn lower_maybe_coroutine_body(
// create a fake body so that the entire rest of the compiler doesn't have to deal with
// this as a special case.
return self.lower_fn_body(decl, contract, |this| {
if attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic))
if find_attr!(attrs, AttributeKind::RustcIntrinsic)
|| this.tcx.is_sdylib_interface_build()
{
let span = this.lower_span(span);
+1
View File
@@ -8,6 +8,7 @@ edition = "2024"
rustc_abi = { path = "../rustc_abi" }
rustc_ast = { path = "../rustc_ast" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_feature = { path = "../rustc_feature" }
rustc_hir = { path = "../rustc_hir" }
@@ -1,22 +1,35 @@
use rustc_ast::token::Token;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{AttrStyle, NodeId, token};
use rustc_data_structures::fx::FxHashMap;
use rustc_feature::{AttributeTemplate, Features};
use rustc_hir::attrs::CfgEntry;
use rustc_hir::{AttrPath, Target};
use rustc_parse::exp;
use rustc_parse::parser::{Parser, Recovery};
use rustc_session::Session;
use rustc_span::{ErrorGuaranteed, Span, sym};
use rustc_session::lint::BuiltinLintDiag;
use rustc_session::lint::builtin::UNREACHABLE_CFG_SELECT_PREDICATES;
use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
use crate::parser::MetaItemOrLitParser;
use crate::{AttributeParser, ParsedDescription, ShouldEmit, parse_cfg_entry};
#[derive(Clone)]
pub enum CfgSelectPredicate {
Cfg(CfgEntry),
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 +128,102 @@ pub fn parse_cfg_select(
}
}
if let Some(features) = features
&& features.enabled(sym::cfg_select)
{
let it = branches
.reachable
.iter()
.map(|(entry, _, _)| CfgSelectPredicate::Cfg(entry.clone()))
.chain(branches.wildcard.as_ref().map(|(t, _, _)| CfgSelectPredicate::Wildcard(*t)))
.chain(
branches.unreachable.iter().map(|(entry, _, _)| CfgSelectPredicate::clone(entry)),
);
lint_unreachable(p, it, lint_node_id);
}
Ok(branches)
}
fn lint_unreachable(
p: &mut Parser<'_>,
predicates: impl Iterator<Item = CfgSelectPredicate>,
lint_node_id: NodeId,
) {
// Symbols that have a known value.
let mut known = FxHashMap::<Symbol, bool>::default();
let mut wildcard_span = None;
let mut it = predicates;
let branch_is_unreachable = |predicate: CfgSelectPredicate, wildcard_span| {
let span = predicate.span();
p.psess.buffer_lint(
UNREACHABLE_CFG_SELECT_PREDICATES,
span,
lint_node_id,
BuiltinLintDiag::UnreachableCfg { span, wildcard_span },
);
};
for predicate in &mut it {
let CfgSelectPredicate::Cfg(ref cfg_entry) = predicate else {
wildcard_span = Some(predicate.span());
break;
};
match cfg_entry {
CfgEntry::Bool(true, _) => {
wildcard_span = Some(predicate.span());
break;
}
CfgEntry::Bool(false, _) => continue,
CfgEntry::NameValue { name, value, .. } => match value {
None => {
// `name` will be false in all subsequent branches.
let current = known.insert(*name, false);
match current {
None => continue,
Some(false) => {
branch_is_unreachable(predicate, None);
break;
}
Some(true) => {
// this branch will be taken, so all subsequent branches are unreachable.
break;
}
}
}
Some(_) => { /* for now we don't bother solving these */ }
},
CfgEntry::Not(inner, _) => match &**inner {
CfgEntry::NameValue { name, value: None, .. } => {
// `name` will be true in all subsequent branches.
let current = known.insert(*name, true);
match current {
None => continue,
Some(true) => {
branch_is_unreachable(predicate, None);
break;
}
Some(false) => {
// this branch will be taken, so all subsequent branches are unreachable.
break;
}
}
}
_ => { /* for now we don't bother solving these */ }
},
CfgEntry::All(_, _) | CfgEntry::Any(_, _) => {
/* for now we don't bother solving these */
}
CfgEntry::Version(..) => { /* don't bother solving these */ }
}
}
for predicate in it {
branch_is_unreachable(predicate, wildcard_span)
}
}
@@ -490,6 +490,7 @@ fn extend(
.collect()
}
}
pub(crate) struct RustcNonConstTraitMethodParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcNonConstTraitMethodParser {
@@ -810,3 +811,21 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
Some(AttributeKind::RustcDefPath(cx.attr_span))
}
}
pub(crate) struct RustcIntrinsicParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcIntrinsicParser {
const PATH: &[Symbol] = &[sym::rustc_intrinsic];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcIntrinsic;
}
pub(crate) struct RustcIntrinsicConstStableIndirectParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcIntrinsicConstStableIndirectParser {
const PATH: &'static [Symbol] = &[sym::rustc_intrinsic_const_stable_indirect];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcIntrinsicConstStableIndirect;
}
@@ -264,6 +264,8 @@ mod late {
Single<WithoutArgs<RustcEffectiveVisibilityParser>>,
Single<WithoutArgs<RustcHasIncoherentInherentImplsParser>>,
Single<WithoutArgs<RustcHiddenTypeOfOpaquesParser>>,
Single<WithoutArgs<RustcIntrinsicConstStableIndirectParser>>,
Single<WithoutArgs<RustcIntrinsicParser>>,
Single<WithoutArgs<RustcLintOptTyParser>>,
Single<WithoutArgs<RustcLintQueryInstabilityParser>>,
Single<WithoutArgs<RustcLintUntrackedQueryInformationParser>>,
@@ -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)
}) {
@@ -540,6 +540,7 @@ pub(crate) fn expand_ext(
.filter(|a| {
a.has_any_name(&[
sym::allow,
sym::expect,
sym::warn,
sym::deny,
sym::forbid,
@@ -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 {
+2
View File
@@ -394,6 +394,8 @@ pub fn internal(&self, feature: Symbol) -> bool {
(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 = "...")`.
@@ -1120,6 +1120,12 @@ pub enum AttributeKind {
/// Represents `#[rustc_if_this_changed]`
RustcIfThisChanged(Span, Option<Symbol>),
/// Represents `#[rustc_intrinsic]`
RustcIntrinsic,
/// Represents `#[rustc_intrinsic_const_stable_indirect]`
RustcIntrinsicConstStableIndirect,
/// Represents `#[rustc_layout]`
RustcLayout(ThinVec<RustcLayoutType>),
@@ -118,6 +118,8 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
RustcHasIncoherentInherentImpls => Yes,
RustcHiddenTypeOfOpaques => No,
RustcIfThisChanged(..) => No,
RustcIntrinsic => Yes,
RustcIntrinsicConstStableIndirect => No,
RustcLayout(..) => No,
RustcLayoutScalarValidRangeEnd(..) => Yes,
RustcLayoutScalarValidRangeStart(..) => Yes,
+7
View File
@@ -998,6 +998,13 @@ 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 = this configuration predicate is never reached
lint_unreachable_cfg_select_predicate_wildcard = 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,14 @@ pub fn decorate_builtin_lint(
}
.decorate_lint(diag);
}
BuiltinLintDiag::UnreachableCfg { span, wildcard_span } => match wildcard_span {
Some(wildcard_span) => {
lints::UnreachableCfgSelectPredicateWildcard { span, wildcard_span }
.decorate_lint(diag)
}
None => lints::UnreachableCfgSelectPredicate { span }.decorate_lint(diag),
},
BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => {
lints::UnusedCrateDependency { extern_crate, local_crate }.decorate_lint(diag)
}
+3
View File
@@ -297,6 +297,9 @@ macro_rules! add_lint_group {
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,
+17
View File
@@ -3340,3 +3340,20 @@ pub(crate) struct UnknownCrateTypesSuggestion {
pub span: Span,
pub snippet: Symbol,
}
#[derive(LintDiagnostic)]
#[diag(lint_unreachable_cfg_select_predicate)]
pub(crate) struct UnreachableCfgSelectPredicate {
#[label]
pub span: Span,
}
#[derive(LintDiagnostic)]
#[diag(lint_unreachable_cfg_select_predicate_wildcard)]
pub(crate) struct UnreachableCfgSelectPredicateWildcard {
#[label(lint_label2)]
pub span: Span,
#[label]
pub wildcard_span: Span,
}
+29
View File
@@ -123,6 +123,7 @@
UNKNOWN_LINTS,
UNNAMEABLE_TEST_ITEMS,
UNNAMEABLE_TYPES,
UNREACHABLE_CFG_SELECT_PREDICATES,
UNREACHABLE_CODE,
UNREACHABLE_PATTERNS,
UNSAFE_ATTR_OUTSIDE_UNSAFE,
@@ -855,6 +856,34 @@
"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.
+4
View File
@@ -748,6 +748,10 @@ pub enum BuiltinLintDiag {
},
UnusedVisibility(Span),
AttributeLint(AttributeLintKind),
UnreachableCfg {
span: Span,
wildcard_span: Option<Span>,
},
}
#[derive(Debug, HashStable_Generic)]
+8 -3
View File
@@ -10,11 +10,11 @@
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::ErrorGuaranteed;
use rustc_hashes::Hash128;
use rustc_hir as hir;
use rustc_hir::attrs::AttributeKind;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
use rustc_hir::limit::Limit;
use rustc_hir::{self as hir, find_attr};
use rustc_index::bit_set::GrowableBitSet;
use rustc_macros::{HashStable, TyDecodable, TyEncodable, extension};
use rustc_span::sym;
@@ -1679,7 +1679,9 @@ pub fn is_doc_notable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
/// the compiler to make some assumptions about its shape; if the user doesn't use a feature gate, they may
/// cause an ICE that we otherwise may want to prevent.
pub fn intrinsic_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::IntrinsicDef> {
if tcx.features().intrinsics() && tcx.has_attr(def_id, sym::rustc_intrinsic) {
if tcx.features().intrinsics()
&& find_attr!(tcx.get_all_attrs(def_id), AttributeKind::RustcIntrinsic)
{
let must_be_overridden = match tcx.hir_node_by_def_id(def_id) {
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { has_body, .. }, .. }) => {
!has_body
@@ -1689,7 +1691,10 @@ pub fn intrinsic_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::Intrinsi
Some(ty::IntrinsicDef {
name: tcx.item_name(def_id),
must_be_overridden,
const_stable: tcx.has_attr(def_id, sym::rustc_intrinsic_const_stable_indirect),
const_stable: find_attr!(
tcx.get_all_attrs(def_id),
AttributeKind::RustcIntrinsicConstStableIndirect
),
})
} else {
None
@@ -1,8 +1,9 @@
//! Check that a body annotated with `#[rustc_force_inline]` will not fail to inline based on its
//! definition alone (irrespective of any specific caller).
use rustc_hir::attrs::InlineAttr;
use rustc_hir::attrs::{AttributeKind, InlineAttr};
use rustc_hir::def_id::DefId;
use rustc_hir::find_attr;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::{Body, TerminatorKind};
use rustc_middle::ty;
@@ -62,7 +63,7 @@ pub(super) fn is_inline_valid_on_fn<'tcx>(
// but at this stage we don't know whether codegen knows the intrinsic,
// so just conservatively don't inline it. This also ensures that we do not
// accidentally inline the body of an intrinsic that *must* be overridden.
if tcx.has_attr(def_id, sym::rustc_intrinsic) {
if find_attr!(tcx.get_all_attrs(def_id), AttributeKind::RustcIntrinsic) {
return Err("callee is an intrinsic");
}
@@ -1,6 +1,7 @@
use rustc_hir::attrs::InlineAttr;
use rustc_hir::attrs::{AttributeKind, InlineAttr};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::find_attr;
use rustc_middle::bug;
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::*;
@@ -43,7 +44,7 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
return true;
}
if tcx.has_attr(def_id, sym::rustc_intrinsic) {
if find_attr!(tcx.get_all_attrs(def_id), AttributeKind::RustcIntrinsic) {
// Intrinsic fallback bodies are always cross-crate inlineable.
// To ensure that the MIR inliner doesn't cluelessly try to inline fallback
// bodies even when the backend would implement something better, we stop
@@ -157,7 +158,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, _: Location) {
// But intrinsics don't have a body that gets assigned to a CGU, so they are
// ignored.
if let Some((fn_def_id, _)) = func.const_fn_def()
&& self.tcx.has_attr(fn_def_id, sym::rustc_intrinsic)
&& find_attr!(tcx.get_all_attrs(fn_def_id), AttributeKind::RustcIntrinsic)
{
return;
}
+2 -2
View File
@@ -313,6 +313,8 @@ fn check_attributes(
| AttributeKind::RustcHasIncoherentInherentImpls
| AttributeKind::RustcHiddenTypeOfOpaques
| AttributeKind::RustcIfThisChanged(..)
| AttributeKind::RustcIntrinsic
| AttributeKind::RustcIntrinsicConstStableIndirect
| AttributeKind::RustcLayout(..)
| AttributeKind::RustcLayoutScalarValidRangeEnd(..)
| AttributeKind::RustcLayoutScalarValidRangeStart(..)
@@ -385,9 +387,7 @@ fn check_attributes(
| sym::rustc_no_mir_inline
| sym::rustc_insignificant_dtor
| sym::rustc_nonnull_optimization_guaranteed
| sym::rustc_intrinsic
| sym::rustc_inherit_overflow_checks
| sym::rustc_intrinsic_const_stable_indirect
| sym::rustc_trivial_field_reads
| sym::rustc_on_unimplemented
| sym::rustc_do_not_const_check
@@ -1,8 +1,9 @@
use super::EMPTY_LOOP;
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::{is_in_panic_handler, is_no_std_crate, sym};
use clippy_utils::{is_in_panic_handler, is_no_std_crate};
use rustc_hir::{Block, Expr, ItemKind, Node};
use rustc_hir::attrs::AttributeKind;
use rustc_hir::{Block, Expr, ItemKind, Node, find_attr};
use rustc_lint::LateContext;
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, loop_block: &Block<'_>) {
@@ -10,7 +11,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, loop_block: &Block<'_
if let Node::Item(parent_node) = cx.tcx.hir_node(parent_hir_id)
&& matches!(parent_node.kind, ItemKind::Fn { .. })
&& let attrs = cx.tcx.hir_attrs(parent_hir_id)
&& attrs.iter().any(|attr| attr.has_name(sym::rustc_intrinsic))
&& find_attr!(attrs, AttributeKind::RustcIntrinsic)
{
// Intrinsic functions are expanded into an empty loop when lowering the AST
// to simplify the job of later passes which might expect any function to have a body.
+2 -2
View File
@@ -4,7 +4,7 @@
#![crate_type = "lib"]
cfg_select! {
true => {}
false => {}
invalid_cfg1 => {}
//~^ WARN unexpected `cfg` condition name
_ => {}
@@ -13,6 +13,6 @@
cfg_select! {
invalid_cfg2 => {}
//~^ WARN unexpected `cfg` condition name
true => {}
false => {}
_ => {}
}
@@ -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() {}
@@ -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`.
@@ -0,0 +1,14 @@
// Make sure that the copied `#[expect]` attr in the derived code does not trigger an unfulfilled
// expectation as it's linked to the original one which is fulfilled.
//
// See <https://github.com/rust-lang/rust/issues/150553#issuecomment-3780810363> for rational.
//@ check-pass
#[expect(non_camel_case_types)]
#[derive(Debug)]
pub struct SCREAMING_CASE {
pub t_ref: i64,
}
fn main() {}
@@ -0,0 +1,14 @@
// Make sure we produce the unfulfilled expectation lint if neither the struct or the
// derived code fulfilled it.
//@ check-pass
#[expect(unexpected_cfgs)]
//~^ WARN this lint expectation is unfulfilled
//~^^ WARN this lint expectation is unfulfilled
#[derive(Debug)]
pub struct MyStruct {
pub t_ref: i64,
}
fn main() {}
@@ -0,0 +1,18 @@
warning: this lint expectation is unfulfilled
--> $DIR/derive-expect-issue-150553-3.rs:6:10
|
LL | #[expect(unexpected_cfgs)]
| ^^^^^^^^^^^^^^^
|
= note: `#[warn(unfulfilled_lint_expectations)]` on by default
warning: this lint expectation is unfulfilled
--> $DIR/derive-expect-issue-150553-3.rs:6:10
|
LL | #[expect(unexpected_cfgs)]
| ^^^^^^^^^^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
warning: 2 warnings emitted
@@ -0,0 +1,22 @@
// Make sure we properly copy the `#[expect]` attr to the derived code and that no
// unfulfilled expectations are trigerred.
//
// See <https://github.com/rust-lang/rust/issues/150553> for rational.
//@ check-pass
#![deny(redundant_lifetimes)]
use std::fmt::Debug;
#[derive(Debug)]
#[expect(redundant_lifetimes)]
pub struct RefWrapper<'a, T>
where
'a: 'static,
T: Debug,
{
pub t_ref: &'a T,
}
fn main() {}
+48 -26
View File
@@ -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! {
@@ -23,40 +24,40 @@ fn arm_rhs_expr_1() -> i32 {
fn arm_rhs_expr_2() -> i32 {
cfg_select! {
true => 1,
false => 2
false => 2,
true => 1
}
}
fn arm_rhs_expr_3() -> i32 {
cfg_select! {
true => 1,
false => 2,
true => { 42 }
false => -1 as i32,
true => 2 + 2,
false => "",
true => if true { 42 } else { 84 }
false => if true { 42 } else { 84 },
true => return 42,
false => loop {}
true => (1, 2),
false => (1, 2,),
true => todo!(),
false => println!("hello"),
any(true) => 1,
any(false) => 2,
any(true) => { 42 }
any(false) => -1 as i32,
any(true) => 2 + 2,
any(false) => "",
any(true) => if true { 42 } else { 84 }
any(false) => if true { 42 } else { 84 },
any(true) => return 42,
any(false) => loop {}
any(true) => (1, 2),
any(false) => (1, 2,),
any(true) => todo!(),
any(false) => println!("hello"),
}
}
fn expand_to_statements() -> i32 {
cfg_select! {
true => {
let a = 1;
a + 1
}
false => {
let b = 2;
b + 1
}
true => {
let a = 1;
a + 1
}
}
}
@@ -76,7 +77,7 @@ fn expand_to_pattern(x: Option<i32>) -> bool {
}
cfg_select! {
true => {
false => {
fn foo() {}
}
_ => {
@@ -88,7 +89,7 @@ fn bar() {}
impl S {
cfg_select! {
true => {
false => {
fn foo() {}
}
_ => {
@@ -99,7 +100,7 @@ fn bar() {}
trait T {
cfg_select! {
true => {
false => {
fn a();
}
_ => {
@@ -110,7 +111,7 @@ trait T {
impl T for S {
cfg_select! {
true => {
false => {
fn a() {}
}
_ => {
@@ -121,7 +122,7 @@ fn b() {}
extern "C" {
cfg_select! {
true => {
false => {
fn puts(s: *const i8) -> i32;
}
_ => {
@@ -133,7 +134,28 @@ fn b() {}
cfg_select! {
_ => {}
true => {}
//~^ WARN unreachable predicate
//~^ WARN unreachable configuration predicate
}
cfg_select! {
true => {}
_ => {}
//~^ WARN unreachable configuration predicate
}
cfg_select! {
unix => {}
not(unix) => {}
_ => {}
//~^ WARN unreachable configuration predicate
}
cfg_select! {
test => {}
test => {}
//~^ WARN unreachable configuration predicate
_ => {}
//~^ WARN unreachable configuration predicate
}
cfg_select! {
+52 -20
View File
@@ -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:161:1
|
LL | / cfg_select! {
LL | |
@@ -16,55 +8,95 @@ LL | | }
| |_^
error: none of the predicates in this `cfg_select` evaluated to true
--> $DIR/cfg_select.rs:144:1
--> $DIR/cfg_select.rs:166: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:170:5
|
LL | => {}
| ^^
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression
--> $DIR/cfg_select.rs:153:5
--> $DIR/cfg_select.rs:175:5
|
LL | () => {}
| ^^ expressions are not allowed here
error[E0539]: malformed `cfg_select` macro input
--> $DIR/cfg_select.rs:158:5
--> $DIR/cfg_select.rs:180: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:185:5
|
LL | a::b => {}
| ^^^^ expected a valid identifier here
error[E0537]: invalid predicate `a`
--> $DIR/cfg_select.rs:168:5
--> $DIR/cfg_select.rs:190:5
|
LL | a() => {}
| ^^^
error: expected one of `(`, `::`, `=>`, or `=`, found `+`
--> $DIR/cfg_select.rs:173:7
--> $DIR/cfg_select.rs:195:7
|
LL | a + 1 => {}
| ^ expected one of `(`, `::`, `=>`, or `=`
error: expected one of `(`, `::`, `=>`, or `=`, found `!`
--> $DIR/cfg_select.rs:179:8
--> $DIR/cfg_select.rs:201: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: unreachable configuration predicate
--> $DIR/cfg_select.rs:142:5
|
LL | true => {}
| ---- always matches
LL | _ => {}
| ^ this configuration predicate is never reached
warning: unreachable configuration predicate
--> $DIR/cfg_select.rs:149:5
|
LL | _ => {}
| ^ this configuration predicate is never reached
warning: unreachable configuration predicate
--> $DIR/cfg_select.rs:155:5
|
LL | test => {}
| ^^^^ this configuration predicate is never reached
warning: unreachable configuration predicate
--> $DIR/cfg_select.rs:157:5
|
LL | _ => {}
| ^ this configuration predicate is never reached
warning: unexpected `cfg` condition name: `a`
--> $DIR/cfg_select.rs:173:5
--> $DIR/cfg_select.rs:195:5
|
LL | a + 1 => {}
| ^ help: found config with similar value: `target_feature = "a"`
@@ -75,7 +107,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:201:5
|
LL | cfg!() => {}
| ^^^
@@ -83,7 +115,7 @@ LL | cfg!() => {}
= help: to expect this configuration use `--check-cfg=cfg(cfg)`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
error: aborting due to 9 previous errors; 3 warnings emitted
error: aborting due to 9 previous errors; 7 warnings emitted
Some errors have detailed explanations: E0537, E0539.
For more information about an error, try `rustc --explain E0537`.