Skip to content

Commit 6b9fb75

Browse files
committed
use feature parser throughout the compiler
1 parent 4b9f5e4 commit 6b9fb75

File tree

14 files changed

+180
-212
lines changed

14 files changed

+180
-212
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3402,6 +3402,7 @@ dependencies = [
34023402
"rustc_errors",
34033403
"rustc_feature",
34043404
"rustc_fluent_macro",
3405+
"rustc_hir",
34053406
"rustc_macros",
34063407
"rustc_session",
34073408
"rustc_span",

compiler/rustc_ast_passes/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ rustc_data_structures = { path = "../rustc_data_structures" }
1414
rustc_errors = { path = "../rustc_errors" }
1515
rustc_feature = { path = "../rustc_feature" }
1616
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
17+
rustc_hir = { path = "../rustc_hir" }
1718
rustc_macros = { path = "../rustc_macros" }
1819
rustc_session = { path = "../rustc_session" }
1920
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 as ast;
22
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
33
use rustc_ast::{NodeId, PatKind, attr, token};
4+
use rustc_attr_parsing::AttributeParser;
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;
@@ -587,17 +590,27 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate)
587590
return;
588591
}
589592
let mut errored = false;
590-
for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) {
593+
594+
if let Some(Attribute::Parsed(AttributeKind::Feature(feature_idents, first_span))) =
595+
AttributeParser::parse_limited(
596+
sess,
597+
&krate.attrs,
598+
sym::feature,
599+
DUMMY_SP,
600+
krate.id,
601+
Some(&features),
602+
)
603+
{
591604
// `feature(...)` used on non-nightly. This is definitely an error.
592605
let mut err = errors::FeatureOnNonNightly {
593-
span: attr.span,
606+
span: first_span,
594607
channel: option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"),
595608
stable_features: vec![],
596609
sugg: None,
597610
};
598611

599612
let mut all_stable = true;
600-
for ident in attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident()) {
613+
for ident in feature_idents {
601614
let name = ident.name;
602615
let stable_since = features
603616
.enabled_lang_features()
@@ -612,7 +625,7 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate)
612625
}
613626
}
614627
if all_stable {
615-
err.sugg = Some(attr.span);
628+
err.sugg = Some(first_span);
616629
}
617630
sess.dcx().emit_err(err);
618631
errored = true;

compiler/rustc_attr_parsing/src/attributes/crate_level.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -190,10 +190,7 @@ impl<S: Stage> CombineAttributeParser<S> for FeatureParser {
190190
const PATH: &[Symbol] = &[sym::feature];
191191
type Item = Ident;
192192
const CONVERT: ConvertFn<Self::Item> = AttributeKind::Feature;
193-
194-
// FIXME: recursion limit is allowed on all targets and ignored,
195-
// even though it should only be valid on crates of course
196-
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
193+
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
197194
const TEMPLATE: AttributeTemplate = template!(List: &["feature1, feature2, ..."]);
198195

199196
fn extend<'c>(

compiler/rustc_expand/src/config.rs

Lines changed: 32 additions & 54 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, AttrKind, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, MetaItemInner,
11-
NodeId, NormalAttr,
10+
self as ast, AttrKind, AttrStyle, Attribute, DUMMY_NODE_ID, HasAttrs, HasTokens, MetaItem,
11+
MetaItemInner, NodeId, NormalAttr,
1212
};
1313
use rustc_attr_parsing as attr;
1414
use rustc_attr_parsing::validate_attr::deny_builtin_meta_unsafety;
@@ -21,16 +21,15 @@ use rustc_feature::{
2121
ACCEPTED_LANG_FEATURES, AttributeSafety, EnabledLangFeature, EnabledLibFeature, Features,
2222
REMOVED_LANG_FEATURES, UNSTABLE_LANG_FEATURES,
2323
};
24+
use rustc_hir::{self as hir, attrs::AttributeKind};
2425
use rustc_session::Session;
2526
use rustc_session::parse::feature_err;
26-
use rustc_span::{STDLIB_STABLE_CRATES, Span, Symbol, sym};
27-
use thin_vec::ThinVec;
27+
use rustc_span::{DUMMY_SP, STDLIB_STABLE_CRATES, Span, Symbol, sym};
2828
use tracing::instrument;
2929

3030
use crate::errors::{
3131
CrateNameInCfgAttr, CrateTypeInCfgAttr, FeatureNotAllowed, FeatureRemoved,
32-
FeatureRemovedReason, InvalidCfg, MalformedFeatureAttribute, MalformedFeatureAttributeHelp,
33-
RemoveExprNotSupported,
32+
FeatureRemovedReason, InvalidCfg, RemoveExprNotSupported,
3433
};
3534

3635
/// A folder that strips out items that do not belong in the current configuration.
@@ -45,44 +44,21 @@ pub struct StripUnconfigured<'a> {
4544
}
4645

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

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

10379
// If the enabled feature is stable, record it.
104-
if let Some(f) = ACCEPTED_LANG_FEATURES.iter().find(|f| name == f.name) {
80+
if let Some(f) = ACCEPTED_LANG_FEATURES.iter().find(|f| name.name == f.name) {
10581
features.set_enabled_lang_feature(EnabledLangFeature {
106-
gate_name: name,
107-
attr_sp: mi.span(),
82+
gate_name: name.name,
83+
attr_sp: name.span,
10884
stable_since: Some(Symbol::intern(f.since)),
10985
});
11086
continue;
@@ -114,38 +90,40 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
11490
// unstable and not also listed as one of the allowed features,
11591
// issue an error.
11692
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 });
93+
if allowed.iter().all(|f| name.name.as_str() != f) {
94+
sess.dcx().emit_err(FeatureNotAllowed { span: name.span, name: name.name });
11995
continue;
12096
}
12197
}
12298

12399
// If the enabled feature is unstable, record it.
124-
if UNSTABLE_LANG_FEATURES.iter().find(|f| name == f.name).is_some() {
100+
if UNSTABLE_LANG_FEATURES.iter().find(|f| name.name == f.name).is_some() {
125101
// When the ICE comes a standard library crate, there's a chance that the person
126102
// hitting the ICE may be using -Zbuild-std or similar with an untested target.
127103
// The bug is probably in the standard library and not the compiler in that case,
128104
// but that doesn't really matter - we want a bug report.
129-
if features.internal(name) && !STDLIB_STABLE_CRATES.contains(&crate_name) {
105+
if features.internal(name.name) && !STDLIB_STABLE_CRATES.contains(&crate_name) {
130106
sess.using_internal_features.store(true, std::sync::atomic::Ordering::Relaxed);
131107
}
132108

133109
features.set_enabled_lang_feature(EnabledLangFeature {
134-
gate_name: name,
135-
attr_sp: mi.span(),
110+
gate_name: name.name,
111+
attr_sp: name.span,
136112
stable_since: None,
137113
});
138114
continue;
139115
}
140116

141117
// Otherwise, the feature is unknown. Enable it as a lib feature.
142118
// 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() });
119+
features.set_enabled_lib_feature(EnabledLibFeature {
120+
gate_name: name.name,
121+
attr_sp: name.span,
122+
});
145123

146124
// Similar to above, detect internal lib features to suppress
147125
// the ICE message that asks for a report.
148-
if features.internal(name) && !STDLIB_STABLE_CRATES.contains(&crate_name) {
126+
if features.internal(name.name) && !STDLIB_STABLE_CRATES.contains(&crate_name) {
149127
sess.using_internal_features.store(true, std::sync::atomic::Ordering::Relaxed);
150128
}
151129
}

compiler/rustc_expand/src/errors.rs

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -143,30 +143,6 @@ pub(crate) struct RecursionLimitReached {
143143
pub crate_name: Symbol,
144144
}
145145

146-
#[derive(Diagnostic)]
147-
#[diag(expand_malformed_feature_attribute, code = E0556)]
148-
pub(crate) struct MalformedFeatureAttribute {
149-
#[primary_span]
150-
pub span: Span,
151-
#[subdiagnostic]
152-
pub help: MalformedFeatureAttributeHelp,
153-
}
154-
155-
#[derive(Subdiagnostic)]
156-
pub(crate) enum MalformedFeatureAttributeHelp {
157-
#[label(expand_expected)]
158-
Label {
159-
#[primary_span]
160-
span: Span,
161-
},
162-
#[suggestion(expand_expected, code = "{suggestion}", applicability = "maybe-incorrect")]
163-
Suggestion {
164-
#[primary_span]
165-
span: Span,
166-
suggestion: Symbol,
167-
},
168-
}
169-
170146
#[derive(Diagnostic)]
171147
#[diag(expand_remove_expr_not_supported)]
172148
pub(crate) struct RemoveExprNotSupported {

compiler/rustc_lint/src/builtin.rs

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

11351135
impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
1136-
fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &hir::Attribute) {
1137-
if attr.has_name(sym::feature)
1138-
&& let Some(items) = attr.meta_item_list()
1139-
{
1140-
for item in items {
1141-
cx.emit_span_lint(UNSTABLE_FEATURES, item.span(), BuiltinUnstableFeatures);
1136+
fn check_attributes(&mut self, cx: &LateContext<'_>, attrs: &[hir::Attribute]) {
1137+
if let Some(features) = find_attr!(attrs, AttributeKind::Feature(features, _) => features) {
1138+
for feature in features {
1139+
cx.emit_span_lint(UNSTABLE_FEATURES, feature.span, BuiltinUnstableFeatures);
11421140
}
11431141
}
11441142
}

tests/ui/empty/empty-attributes.stderr

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,6 @@ LL | #![forbid()]
4343
|
4444
= note: attribute `forbid` with an empty list has no effect
4545

46-
error: unused attribute
47-
--> $DIR/empty-attributes.rs:7:1
48-
|
49-
LL | #![feature()]
50-
| ^^^^^^^^^^^^^ help: remove this attribute
51-
|
52-
= note: attribute `feature` with an empty list has no effect
53-
5446
error: unused attribute
5547
--> $DIR/empty-attributes.rs:9:1
5648
|
@@ -63,5 +55,11 @@ error: unused attribute
6355
LL | #[target_feature()]
6456
| ^^^^^^^^^^^^^^^^^^^ help: remove this attribute
6557

58+
error: unused attribute
59+
--> $DIR/empty-attributes.rs:7:1
60+
|
61+
LL | #![feature()]
62+
| ^^^^^^^^^^^^^ help: remove this attribute
63+
6664
error: aborting due to 8 previous errors
6765

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
#![forbid(unstable_features)]
22
#![feature(intrinsics)] //~ ERROR unstable feature
33

4-
fn main() { }
4+
fn main() {}
Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,3 @@
1-
error[E0556]: malformed `feature` attribute input
2-
--> $DIR/gated-bad-feature.rs:1:25
3-
|
4-
LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)]
5-
| ^^^^^^^^ help: expected just one word: `foo`
6-
7-
error[E0556]: malformed `feature` attribute input
8-
--> $DIR/gated-bad-feature.rs:1:35
9-
|
10-
LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)]
11-
| ^^^^^^^^^^^ help: expected just one word: `foo`
12-
131
error[E0557]: feature has been removed
142
--> $DIR/gated-bad-feature.rs:8:12
153
|
@@ -18,17 +6,41 @@ LL | #![feature(test_removed_feature)]
186
|
197
= note: removed in 1.0.0
208

21-
error: malformed `feature` attribute input
9+
error[E0565]: malformed `feature` attribute input
10+
--> $DIR/gated-bad-feature.rs:1:1
11+
|
12+
LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)]
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^
14+
| | |
15+
| | didn't expect any arguments here
16+
| help: must be of the form: `#![feature(feature1, feature2, ...)]`
17+
18+
error[E0565]: malformed `feature` attribute input
19+
--> $DIR/gated-bad-feature.rs:1:1
20+
|
21+
LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)]
22+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------^^^^^^^
23+
| | |
24+
| | didn't expect any arguments here
25+
| help: must be of the form: `#![feature(feature1, feature2, ...)]`
26+
27+
error[E0539]: malformed `feature` attribute input
2228
--> $DIR/gated-bad-feature.rs:6:1
2329
|
2430
LL | #![feature]
25-
| ^^^^^^^^^^^ help: must be of the form: `#![feature(name1, name2, ...)]`
31+
| ^^^^^^^^^^^
32+
| |
33+
| expected this to be a list
34+
| help: must be of the form: `#![feature(feature1, feature2, ...)]`
2635

27-
error: malformed `feature` attribute input
36+
error[E0539]: malformed `feature` attribute input
2837
--> $DIR/gated-bad-feature.rs:7:1
2938
|
3039
LL | #![feature = "foo"]
31-
| ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![feature(name1, name2, ...)]`
40+
| ^^^^^^^^^^^^^^^^^^^
41+
| |
42+
| expected this to be a list
43+
| help: must be of the form: `#![feature(feature1, feature2, ...)]`
3244

3345
error[E0635]: unknown feature `foo_bar_baz`
3446
--> $DIR/gated-bad-feature.rs:1:12
@@ -44,5 +56,5 @@ LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)]
4456

4557
error: aborting due to 7 previous errors
4658

47-
Some errors have detailed explanations: E0556, E0557, E0635.
48-
For more information about an error, try `rustc --explain E0556`.
59+
Some errors have detailed explanations: E0539, E0557, E0565, E0635.
60+
For more information about an error, try `rustc --explain E0539`.

0 commit comments

Comments
 (0)