mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
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:
@@ -3539,6 +3539,7 @@ dependencies = [
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_hir",
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -748,6 +748,10 @@ pub enum BuiltinLintDiag {
|
||||
},
|
||||
UnusedVisibility(Span),
|
||||
AttributeLint(AttributeLintKind),
|
||||
UnreachableCfg {
|
||||
span: Span,
|
||||
wildcard_span: Option<Span>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, HashStable_Generic)]
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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() {}
|
||||
@@ -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! {
|
||||
|
||||
@@ -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`.
|
||||
|
||||
Reference in New Issue
Block a user