Skip to content

Commit cf9ab2d

Browse files
JonathanBrouwerjdonszelmann
andcommitted
Use feature parser throughout the compiler
Co-authored-by: jdonszelmann <janabent@gmail.com>
1 parent 2a58411 commit cf9ab2d

5 files changed

Lines changed: 66 additions & 94 deletions

File tree

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_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_lint/src/builtin.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,12 +1120,10 @@ declare_lint_pass!(
11201120
);
11211121

11221122
impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
1123-
fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &hir::Attribute) {
1124-
if attr.has_name(sym::feature)
1125-
&& let Some(items) = attr.meta_item_list()
1126-
{
1127-
for item in items {
1128-
cx.emit_span_lint(UNSTABLE_FEATURES, item.span(), BuiltinUnstableFeatures);
1123+
fn check_attributes(&mut self, cx: &LateContext<'_>, attrs: &[hir::Attribute]) {
1124+
if let Some(features) = find_attr!(attrs, Feature(features, _) => features) {
1125+
for feature in features {
1126+
cx.emit_span_lint(UNSTABLE_FEATURES, feature.span, BuiltinUnstableFeatures);
11291127
}
11301128
}
11311129
}

0 commit comments

Comments
 (0)