Skip to content

Commit b70562e

Browse files
committed
Auto merge of #152985 - JonathanBrouwer:convert-feature, r=<try>
Port `#[feature]` to the new attribute system try-job: x86_64-rust-for-linux
2 parents 1500f0f + eb86917 commit b70562e

25 files changed

Lines changed: 333 additions & 292 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3515,6 +3515,7 @@ dependencies = [
35153515
"rustc_data_structures",
35163516
"rustc_errors",
35173517
"rustc_feature",
3518+
"rustc_hir",
35183519
"rustc_macros",
35193520
"rustc_session",
35203521
"rustc_span",

compiler/rustc_ast_passes/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ rustc_attr_parsing = { path = "../rustc_attr_parsing" }
1313
rustc_data_structures = { path = "../rustc_data_structures" }
1414
rustc_errors = { path = "../rustc_errors" }
1515
rustc_feature = { path = "../rustc_feature" }
16+
rustc_hir = { path = "../rustc_hir" }
1617
rustc_macros = { path = "../rustc_macros" }
1718
rustc_session = { path = "../rustc_session" }
1819
rustc_span = { path = "../rustc_span" }

compiler/rustc_ast_passes/src/feature_gate.rs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
22
use rustc_ast::{self as ast, AttrVec, NodeId, PatKind, attr, token};
3+
use rustc_attr_parsing::AttributeParser;
34
use rustc_errors::msg;
45
use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, Features};
6+
use rustc_hir::Attribute;
7+
use rustc_hir::attrs::AttributeKind;
58
use rustc_session::Session;
69
use rustc_session::parse::{feature_err, feature_warn};
710
use rustc_span::source_map::Spanned;
8-
use rustc_span::{Span, Symbol, sym};
11+
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
912
use thin_vec::ThinVec;
1013

1114
use crate::errors;
@@ -636,17 +639,27 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate)
636639
return;
637640
}
638641
let mut errored = false;
639-
for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) {
642+
643+
if let Some(Attribute::Parsed(AttributeKind::Feature(feature_idents, first_span))) =
644+
AttributeParser::parse_limited(
645+
sess,
646+
&krate.attrs,
647+
sym::feature,
648+
DUMMY_SP,
649+
krate.id,
650+
Some(&features),
651+
)
652+
{
640653
// `feature(...)` used on non-nightly. This is definitely an error.
641654
let mut err = errors::FeatureOnNonNightly {
642-
span: attr.span,
655+
span: first_span,
643656
channel: option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"),
644657
stable_features: vec![],
645658
sugg: None,
646659
};
647660

648661
let mut all_stable = true;
649-
for ident in attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident()) {
662+
for ident in feature_idents {
650663
let name = ident.name;
651664
let stable_since = features
652665
.enabled_lang_features()
@@ -661,7 +674,7 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate)
661674
}
662675
}
663676
if all_stable {
664-
err.sugg = Some(attr.span);
677+
err.sugg = Some(first_span);
665678
}
666679
sess.dcx().emit_err(err);
667680
errored = true;

compiler/rustc_attr_parsing/src/attributes/crate_level.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,3 +301,49 @@ impl<S: Stage> NoArgsAttributeParser<S> for DefaultLibAllocatorParser {
301301
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
302302
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::DefaultLibAllocator;
303303
}
304+
305+
pub(crate) struct FeatureParser;
306+
307+
impl<S: Stage> CombineAttributeParser<S> for FeatureParser {
308+
const PATH: &[Symbol] = &[sym::feature];
309+
type Item = Ident;
310+
const CONVERT: ConvertFn<Self::Item> = AttributeKind::Feature;
311+
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
312+
const TEMPLATE: AttributeTemplate = template!(List: &["feature1, feature2, ..."]);
313+
314+
fn extend(
315+
cx: &mut AcceptContext<'_, '_, S>,
316+
args: &ArgParser,
317+
) -> impl IntoIterator<Item = Self::Item> {
318+
let ArgParser::List(list) = args else {
319+
cx.expected_list(cx.attr_span, args);
320+
return Vec::new();
321+
};
322+
323+
if list.is_empty() {
324+
cx.warn_empty_attribute(cx.attr_span);
325+
}
326+
327+
let mut res = Vec::new();
328+
329+
for elem in list.mixed() {
330+
let Some(elem) = elem.meta_item() else {
331+
cx.expected_identifier(elem.span());
332+
continue;
333+
};
334+
if let Err(arg_span) = elem.args().no_args() {
335+
cx.expected_no_args(arg_span);
336+
continue;
337+
}
338+
339+
let path = elem.path();
340+
let Some(ident) = path.word() else {
341+
cx.expected_identifier(path.span());
342+
continue;
343+
};
344+
res.push(ident);
345+
}
346+
347+
res
348+
}
349+
}

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ attribute_parsers!(
157157
Combine<AllowInternalUnstableParser>,
158158
Combine<CrateTypeParser>,
159159
Combine<DebuggerViualizerParser>,
160+
Combine<FeatureParser>,
160161
Combine<ForceTargetFeatureParser>,
161162
Combine<LinkParser>,
162163
Combine<ReprParser>,

compiler/rustc_error_codes/src/error_codes/E0556.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
#### Note: this error code is no longer emitted by the compiler.
2+
13
The `feature` attribute was badly formed.
24

35
Erroneous code example:
46

5-
```compile_fail,E0556
7+
```compile_fail
68
#![feature(foo_bar_baz, foo(bar), foo = "baz", foo)] // error!
79
#![feature] // error!
810
#![feature = "foo"] // error!

compiler/rustc_error_codes/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ macro_rules! error_codes {
334334
0551,
335335
0552,
336336
0554,
337-
0556,
337+
0556, // REMOVED: merged with other attribute error codes
338338
0557,
339339
0559,
340340
0560,

compiler/rustc_expand/src/config.rs

Lines changed: 43 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ use rustc_ast::tokenstream::{
77
AttrTokenStream, AttrTokenTree, LazyAttrTokenStream, Spacing, TokenTree,
88
};
99
use rustc_ast::{
10-
self as ast, AttrItemKind, AttrKind, AttrStyle, Attribute, EarlyParsedAttribute, HasAttrs,
11-
HasTokens, MetaItem, MetaItemInner, NodeId, NormalAttr,
10+
self as ast, AttrItemKind, AttrKind, AttrStyle, Attribute, DUMMY_NODE_ID, EarlyParsedAttribute,
11+
HasAttrs, HasTokens, MetaItem, MetaItemInner, NodeId, NormalAttr,
1212
};
1313
use rustc_attr_parsing as attr;
1414
use rustc_attr_parsing::{
@@ -20,18 +20,19 @@ use rustc_feature::{
2020
ACCEPTED_LANG_FEATURES, EnabledLangFeature, EnabledLibFeature, Features, REMOVED_LANG_FEATURES,
2121
UNSTABLE_LANG_FEATURES,
2222
};
23-
use rustc_hir::Target;
23+
use rustc_hir::attrs::AttributeKind;
24+
use rustc_hir::{
25+
Target, {self as hir},
26+
};
2427
use rustc_parse::parser::Recovery;
2528
use rustc_session::Session;
2629
use rustc_session::parse::feature_err;
27-
use rustc_span::{STDLIB_STABLE_CRATES, Span, Symbol, sym};
28-
use thin_vec::ThinVec;
30+
use rustc_span::{DUMMY_SP, STDLIB_STABLE_CRATES, Span, Symbol, sym};
2931
use tracing::instrument;
3032

3133
use crate::errors::{
3234
CrateNameInCfgAttr, CrateTypeInCfgAttr, FeatureNotAllowed, FeatureRemoved,
33-
FeatureRemovedReason, InvalidCfg, MalformedFeatureAttribute, MalformedFeatureAttributeHelp,
34-
RemoveExprNotSupported,
35+
FeatureRemovedReason, InvalidCfg, RemoveExprNotSupported,
3536
};
3637

3738
/// A folder that strips out items that do not belong in the current configuration.
@@ -46,44 +47,23 @@ pub struct StripUnconfigured<'a> {
4647
}
4748

4849
pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -> Features {
49-
fn feature_list(attr: &Attribute) -> ThinVec<ast::MetaItemInner> {
50-
if attr.has_name(sym::feature)
51-
&& let Some(list) = attr.meta_item_list()
52-
{
53-
list
54-
} else {
55-
ThinVec::new()
56-
}
57-
}
58-
5950
let mut features = Features::default();
6051

61-
// Process all features enabled in the code.
62-
for attr in krate_attrs {
63-
for mi in feature_list(attr) {
64-
let name = match mi.ident() {
65-
Some(ident) if mi.is_word() => ident.name,
66-
Some(ident) => {
67-
sess.dcx().emit_err(MalformedFeatureAttribute {
68-
span: mi.span(),
69-
help: MalformedFeatureAttributeHelp::Suggestion {
70-
span: mi.span(),
71-
suggestion: ident.name,
72-
},
73-
});
74-
continue;
75-
}
76-
None => {
77-
sess.dcx().emit_err(MalformedFeatureAttribute {
78-
span: mi.span(),
79-
help: MalformedFeatureAttributeHelp::Label { span: mi.span() },
80-
});
81-
continue;
82-
}
83-
};
84-
52+
if let Some(hir::Attribute::Parsed(AttributeKind::Feature(feature_idents, _))) =
53+
AttributeParser::parse_limited(
54+
sess,
55+
krate_attrs,
56+
sym::feature,
57+
DUMMY_SP,
58+
DUMMY_NODE_ID,
59+
Some(&features),
60+
)
61+
{
62+
for feature_ident in feature_idents {
8563
// If the enabled feature has been removed, issue an error.
86-
if let Some(f) = REMOVED_LANG_FEATURES.iter().find(|f| name == f.feature.name) {
64+
if let Some(f) =
65+
REMOVED_LANG_FEATURES.iter().find(|f| feature_ident.name == f.feature.name)
66+
{
8767
let pull_note = if let Some(pull) = f.pull {
8868
format!(
8969
"; see <https://github.com/rust-lang/rust/pull/{pull}> for more information",
@@ -92,7 +72,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
9272
"".to_owned()
9373
};
9474
sess.dcx().emit_err(FeatureRemoved {
95-
span: mi.span(),
75+
span: feature_ident.span,
9676
reason: f.reason.map(|reason| FeatureRemovedReason { reason }),
9777
removed_rustc_version: f.feature.since,
9878
pull_note,
@@ -101,10 +81,10 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
10181
}
10282

10383
// If the enabled feature is stable, record it.
104-
if let Some(f) = ACCEPTED_LANG_FEATURES.iter().find(|f| name == f.name) {
84+
if let Some(f) = ACCEPTED_LANG_FEATURES.iter().find(|f| feature_ident.name == f.name) {
10585
features.set_enabled_lang_feature(EnabledLangFeature {
106-
gate_name: name,
107-
attr_sp: mi.span(),
86+
gate_name: feature_ident.name,
87+
attr_sp: feature_ident.span,
10888
stable_since: Some(Symbol::intern(f.since)),
10989
});
11090
continue;
@@ -114,38 +94,46 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
11494
// unstable and not also listed as one of the allowed features,
11595
// issue an error.
11696
if let Some(allowed) = sess.opts.unstable_opts.allow_features.as_ref() {
117-
if allowed.iter().all(|f| name.as_str() != f) {
118-
sess.dcx().emit_err(FeatureNotAllowed { span: mi.span(), name });
97+
if allowed.iter().all(|f| feature_ident.name.as_str() != f) {
98+
sess.dcx().emit_err(FeatureNotAllowed {
99+
span: feature_ident.span,
100+
name: feature_ident.name,
101+
});
119102
continue;
120103
}
121104
}
122105

123106
// If the enabled feature is unstable, record it.
124-
if UNSTABLE_LANG_FEATURES.iter().find(|f| name == f.name).is_some() {
107+
if UNSTABLE_LANG_FEATURES.iter().find(|f| feature_ident.name == f.name).is_some() {
125108
// When the ICE comes from a standard library crate, there's a chance that the person
126109
// hitting the ICE may be using -Zbuild-std or similar with an untested target.
127110
// The bug is probably in the standard library and not the compiler in that case,
128111
// but that doesn't really matter - we want a bug report.
129-
if features.internal(name) && !STDLIB_STABLE_CRATES.contains(&crate_name) {
112+
if features.internal(feature_ident.name)
113+
&& !STDLIB_STABLE_CRATES.contains(&crate_name)
114+
{
130115
sess.using_internal_features.store(true, std::sync::atomic::Ordering::Relaxed);
131116
}
132117

133118
features.set_enabled_lang_feature(EnabledLangFeature {
134-
gate_name: name,
135-
attr_sp: mi.span(),
119+
gate_name: feature_ident.name,
120+
attr_sp: feature_ident.span,
136121
stable_since: None,
137122
});
138123
continue;
139124
}
140125

141126
// Otherwise, the feature is unknown. Enable it as a lib feature.
142127
// It will be checked later whether the feature really exists.
143-
features
144-
.set_enabled_lib_feature(EnabledLibFeature { gate_name: name, attr_sp: mi.span() });
128+
features.set_enabled_lib_feature(EnabledLibFeature {
129+
gate_name: feature_ident.name,
130+
attr_sp: feature_ident.span,
131+
});
145132

146133
// Similar to above, detect internal lib features to suppress
147134
// the ICE message that asks for a report.
148-
if features.internal(name) && !STDLIB_STABLE_CRATES.contains(&crate_name) {
135+
if features.internal(feature_ident.name) && !STDLIB_STABLE_CRATES.contains(&crate_name)
136+
{
149137
sess.using_internal_features.store(true, std::sync::atomic::Ordering::Relaxed);
150138
}
151139
}

compiler/rustc_expand/src/errors.rs

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -183,34 +183,6 @@ pub(crate) struct RecursionLimitReached {
183183
pub crate_name: Symbol,
184184
}
185185

186-
#[derive(Diagnostic)]
187-
#[diag("malformed `feature` attribute input", code = E0556)]
188-
pub(crate) struct MalformedFeatureAttribute {
189-
#[primary_span]
190-
pub span: Span,
191-
#[subdiagnostic]
192-
pub help: MalformedFeatureAttributeHelp,
193-
}
194-
195-
#[derive(Subdiagnostic)]
196-
pub(crate) enum MalformedFeatureAttributeHelp {
197-
#[label("expected just one word")]
198-
Label {
199-
#[primary_span]
200-
span: Span,
201-
},
202-
#[suggestion(
203-
"expected just one word",
204-
code = "{suggestion}",
205-
applicability = "maybe-incorrect"
206-
)]
207-
Suggestion {
208-
#[primary_span]
209-
span: Span,
210-
suggestion: Symbol,
211-
},
212-
}
213-
214186
#[derive(Diagnostic)]
215187
#[diag("removing an expression is not supported in this position")]
216188
pub(crate) struct RemoveExprNotSupported {

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -954,6 +954,9 @@ pub enum AttributeKind {
954954
/// Represents `#[export_stable]`.
955955
ExportStable,
956956

957+
/// Represents `#[feature(...)]`
958+
Feature(ThinVec<Ident>, Span),
959+
957960
/// Represents `#[ffi_const]`.
958961
FfiConst(Span),
959962

0 commit comments

Comments
 (0)