Skip to content

Commit c7f5f3e

Browse files
committed
Auto merge of #152294 - JonathanBrouwer:rollup-ygNTxe8, r=JonathanBrouwer
Rollup of 3 pull requests Successful merges: - #149960 (add `unreachable_cfg_select_predicates` lint) - #152168 (Port `rustc_intrinsic_const_stable_indirect` and `rustc_intrinsic` to the new attribute parser) - #152289 (Also duplicate `#[expect]` attribute in `#[derive]`-ed code)
2 parents 8c5605e + fced230 commit c7f5f3e

32 files changed

Lines changed: 443 additions & 90 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3539,6 +3539,7 @@ dependencies = [
35393539
"rustc_abi",
35403540
"rustc_ast",
35413541
"rustc_ast_pretty",
3542+
"rustc_data_structures",
35423543
"rustc_errors",
35433544
"rustc_feature",
35443545
"rustc_hir",

compiler/rustc_ast_lowering/src/item.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1397,7 +1397,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
13971397
// create a fake body so that the entire rest of the compiler doesn't have to deal with
13981398
// this as a special case.
13991399
return self.lower_fn_body(decl, contract, |this| {
1400-
if attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic))
1400+
if find_attr!(attrs, AttributeKind::RustcIntrinsic)
14011401
|| this.tcx.is_sdylib_interface_build()
14021402
{
14031403
let span = this.lower_span(span);

compiler/rustc_attr_parsing/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ edition = "2024"
88
rustc_abi = { path = "../rustc_abi" }
99
rustc_ast = { path = "../rustc_ast" }
1010
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
11+
rustc_data_structures = { path = "../rustc_data_structures" }
1112
rustc_errors = { path = "../rustc_errors" }
1213
rustc_feature = { path = "../rustc_feature" }
1314
rustc_hir = { path = "../rustc_hir" }

compiler/rustc_attr_parsing/src/attributes/cfg_select.rs

Lines changed: 111 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,35 @@
11
use rustc_ast::token::Token;
22
use rustc_ast::tokenstream::TokenStream;
33
use rustc_ast::{AttrStyle, NodeId, token};
4+
use rustc_data_structures::fx::FxHashMap;
45
use rustc_feature::{AttributeTemplate, Features};
56
use rustc_hir::attrs::CfgEntry;
67
use rustc_hir::{AttrPath, Target};
78
use rustc_parse::exp;
89
use rustc_parse::parser::{Parser, Recovery};
910
use rustc_session::Session;
10-
use rustc_span::{ErrorGuaranteed, Span, sym};
11+
use rustc_session::lint::BuiltinLintDiag;
12+
use rustc_session::lint::builtin::UNREACHABLE_CFG_SELECT_PREDICATES;
13+
use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
1114

1215
use crate::parser::MetaItemOrLitParser;
1316
use crate::{AttributeParser, ParsedDescription, ShouldEmit, parse_cfg_entry};
1417

18+
#[derive(Clone)]
1519
pub enum CfgSelectPredicate {
1620
Cfg(CfgEntry),
1721
Wildcard(Token),
1822
}
1923

24+
impl CfgSelectPredicate {
25+
fn span(&self) -> Span {
26+
match self {
27+
CfgSelectPredicate::Cfg(cfg_entry) => cfg_entry.span(),
28+
CfgSelectPredicate::Wildcard(token) => token.span,
29+
}
30+
}
31+
}
32+
2033
#[derive(Default)]
2134
pub struct CfgSelectBranches {
2235
/// All the conditional branches.
@@ -115,5 +128,102 @@ pub fn parse_cfg_select(
115128
}
116129
}
117130

131+
if let Some(features) = features
132+
&& features.enabled(sym::cfg_select)
133+
{
134+
let it = branches
135+
.reachable
136+
.iter()
137+
.map(|(entry, _, _)| CfgSelectPredicate::Cfg(entry.clone()))
138+
.chain(branches.wildcard.as_ref().map(|(t, _, _)| CfgSelectPredicate::Wildcard(*t)))
139+
.chain(
140+
branches.unreachable.iter().map(|(entry, _, _)| CfgSelectPredicate::clone(entry)),
141+
);
142+
143+
lint_unreachable(p, it, lint_node_id);
144+
}
145+
118146
Ok(branches)
119147
}
148+
149+
fn lint_unreachable(
150+
p: &mut Parser<'_>,
151+
predicates: impl Iterator<Item = CfgSelectPredicate>,
152+
lint_node_id: NodeId,
153+
) {
154+
// Symbols that have a known value.
155+
let mut known = FxHashMap::<Symbol, bool>::default();
156+
let mut wildcard_span = None;
157+
let mut it = predicates;
158+
159+
let branch_is_unreachable = |predicate: CfgSelectPredicate, wildcard_span| {
160+
let span = predicate.span();
161+
p.psess.buffer_lint(
162+
UNREACHABLE_CFG_SELECT_PREDICATES,
163+
span,
164+
lint_node_id,
165+
BuiltinLintDiag::UnreachableCfg { span, wildcard_span },
166+
);
167+
};
168+
169+
for predicate in &mut it {
170+
let CfgSelectPredicate::Cfg(ref cfg_entry) = predicate else {
171+
wildcard_span = Some(predicate.span());
172+
break;
173+
};
174+
175+
match cfg_entry {
176+
CfgEntry::Bool(true, _) => {
177+
wildcard_span = Some(predicate.span());
178+
break;
179+
}
180+
CfgEntry::Bool(false, _) => continue,
181+
CfgEntry::NameValue { name, value, .. } => match value {
182+
None => {
183+
// `name` will be false in all subsequent branches.
184+
let current = known.insert(*name, false);
185+
186+
match current {
187+
None => continue,
188+
Some(false) => {
189+
branch_is_unreachable(predicate, None);
190+
break;
191+
}
192+
Some(true) => {
193+
// this branch will be taken, so all subsequent branches are unreachable.
194+
break;
195+
}
196+
}
197+
}
198+
Some(_) => { /* for now we don't bother solving these */ }
199+
},
200+
CfgEntry::Not(inner, _) => match &**inner {
201+
CfgEntry::NameValue { name, value: None, .. } => {
202+
// `name` will be true in all subsequent branches.
203+
let current = known.insert(*name, true);
204+
205+
match current {
206+
None => continue,
207+
Some(true) => {
208+
branch_is_unreachable(predicate, None);
209+
break;
210+
}
211+
Some(false) => {
212+
// this branch will be taken, so all subsequent branches are unreachable.
213+
break;
214+
}
215+
}
216+
}
217+
_ => { /* for now we don't bother solving these */ }
218+
},
219+
CfgEntry::All(_, _) | CfgEntry::Any(_, _) => {
220+
/* for now we don't bother solving these */
221+
}
222+
CfgEntry::Version(..) => { /* don't bother solving these */ }
223+
}
224+
}
225+
226+
for predicate in it {
227+
branch_is_unreachable(predicate, wildcard_span)
228+
}
229+
}

compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,7 @@ impl<S: Stage> CombineAttributeParser<S> for RustcMirParser {
490490
.collect()
491491
}
492492
}
493+
493494
pub(crate) struct RustcNonConstTraitMethodParser;
494495

495496
impl<S: Stage> NoArgsAttributeParser<S> for RustcNonConstTraitMethodParser {
@@ -810,3 +811,21 @@ impl<S: Stage> SingleAttributeParser<S> for RustcDefPath {
810811
Some(AttributeKind::RustcDefPath(cx.attr_span))
811812
}
812813
}
814+
815+
pub(crate) struct RustcIntrinsicParser;
816+
817+
impl<S: Stage> NoArgsAttributeParser<S> for RustcIntrinsicParser {
818+
const PATH: &[Symbol] = &[sym::rustc_intrinsic];
819+
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
820+
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
821+
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcIntrinsic;
822+
}
823+
824+
pub(crate) struct RustcIntrinsicConstStableIndirectParser;
825+
826+
impl<S: Stage> NoArgsAttributeParser<S> for RustcIntrinsicConstStableIndirectParser {
827+
const PATH: &'static [Symbol] = &[sym::rustc_intrinsic_const_stable_indirect];
828+
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
829+
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
830+
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcIntrinsicConstStableIndirect;
831+
}

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,8 @@ attribute_parsers!(
264264
Single<WithoutArgs<RustcEffectiveVisibilityParser>>,
265265
Single<WithoutArgs<RustcHasIncoherentInherentImplsParser>>,
266266
Single<WithoutArgs<RustcHiddenTypeOfOpaquesParser>>,
267+
Single<WithoutArgs<RustcIntrinsicConstStableIndirectParser>>,
268+
Single<WithoutArgs<RustcIntrinsicParser>>,
267269
Single<WithoutArgs<RustcLintOptTyParser>>,
268270
Single<WithoutArgs<RustcLintQueryInstabilityParser>>,
269271
Single<WithoutArgs<RustcLintUntrackedQueryInformationParser>>,

compiler/rustc_builtin_macros/src/cfg_select.rs

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
use rustc_ast::tokenstream::TokenStream;
22
use rustc_ast::{Expr, ast};
33
use rustc_attr_parsing as attr;
4-
use rustc_attr_parsing::{
5-
CfgSelectBranches, CfgSelectPredicate, EvalConfigResult, parse_cfg_select,
6-
};
4+
use rustc_attr_parsing::{CfgSelectBranches, EvalConfigResult, parse_cfg_select};
75
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult};
86
use rustc_span::{Ident, Span, sym};
97
use smallvec::SmallVec;
108

11-
use crate::errors::{CfgSelectNoMatches, CfgSelectUnreachable};
9+
use crate::errors::CfgSelectNoMatches;
1210

1311
/// This intermediate structure is used to emit parse errors for the branches that are not chosen.
1412
/// 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>(
7573
ecx.current_expansion.lint_node_id,
7674
) {
7775
Ok(mut branches) => {
78-
if let Some((underscore, _, _)) = branches.wildcard {
79-
// Warn for every unreachable predicate. We store the fully parsed branch for rustfmt.
80-
for (predicate, _, _) in &branches.unreachable {
81-
let span = match predicate {
82-
CfgSelectPredicate::Wildcard(underscore) => underscore.span,
83-
CfgSelectPredicate::Cfg(cfg) => cfg.span(),
84-
};
85-
let err = CfgSelectUnreachable { span, wildcard_span: underscore.span };
86-
ecx.dcx().emit_warn(err);
87-
}
88-
}
89-
9076
if let Some((selected_tts, selected_span)) = branches.pop_first_match(|cfg| {
9177
matches!(attr::eval_config_entry(&ecx.sess, cfg), EvalConfigResult::True)
9278
}) {

compiler/rustc_builtin_macros/src/deriving/generic/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,7 @@ impl<'a> TraitDef<'a> {
540540
.filter(|a| {
541541
a.has_any_name(&[
542542
sym::allow,
543+
sym::expect,
543544
sym::warn,
544545
sym::deny,
545546
sym::forbid,

compiler/rustc_builtin_macros/src/errors.rs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,17 +1086,6 @@ pub(crate) struct CfgSelectNoMatches {
10861086
pub span: Span,
10871087
}
10881088

1089-
#[derive(Diagnostic)]
1090-
#[diag("unreachable predicate")]
1091-
pub(crate) struct CfgSelectUnreachable {
1092-
#[primary_span]
1093-
#[label("this predicate is never reached")]
1094-
pub span: Span,
1095-
1096-
#[label("always matches")]
1097-
pub wildcard_span: Span,
1098-
}
1099-
11001089
#[derive(Diagnostic)]
11011090
#[diag("`#[eii_declaration(...)]` is only valid on macros")]
11021091
pub(crate) struct EiiExternTargetExpectedMacro {

compiler/rustc_feature/src/unstable.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,8 @@ declare_features! (
394394
(unstable, cfg_sanitize, "1.41.0", Some(39699)),
395395
/// Allows `cfg(sanitizer_cfi_generalize_pointers)` and `cfg(sanitizer_cfi_normalize_integers)`.
396396
(unstable, cfg_sanitizer_cfi, "1.77.0", Some(89653)),
397+
/// Provides a native way to easily manage multiple conditional flags without having to rewrite each clause multiple times.
398+
(unstable, cfg_select, "CURRENT_RUSTC_VERSION", Some(115585)),
397399
/// Allows `cfg(target(abi = "..."))`.
398400
(unstable, cfg_target_compact, "1.63.0", Some(96901)),
399401
/// Allows `cfg(target_has_atomic_load_store = "...")`.

0 commit comments

Comments
 (0)