Skip to content

Commit a01ba39

Browse files
committed
feature_gate: Merge various attribute gating functions
1 parent 966d96c commit a01ba39

12 files changed

+54
-103
lines changed

src/libsyntax/ext/expand.rs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use syntax_pos::{Span, DUMMY_SP, FileName};
2626
use rustc_data_structures::fx::FxHashMap;
2727
use rustc_data_structures::sync::Lrc;
2828
use std::io::ErrorKind;
29-
use std::{iter, mem};
29+
use std::{iter, mem, slice};
3030
use std::ops::DerefMut;
3131
use std::rc::Rc;
3232
use std::path::PathBuf;
@@ -1019,7 +1019,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
10191019
fn check_attributes(&mut self, attrs: &[ast::Attribute]) {
10201020
let features = self.cx.ecfg.features.unwrap();
10211021
for attr in attrs.iter() {
1022-
self.check_attribute_inner(attr, features);
1022+
feature_gate::check_attribute(attr, self.cx.parse_sess, features);
10231023

10241024
// macros are expanded before any lint passes so this warning has to be hardcoded
10251025
if attr.path == sym::derive {
@@ -1029,15 +1029,6 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
10291029
}
10301030
}
10311031
}
1032-
1033-
fn check_attribute(&mut self, at: &ast::Attribute) {
1034-
let features = self.cx.ecfg.features.unwrap();
1035-
self.check_attribute_inner(at, features);
1036-
}
1037-
1038-
fn check_attribute_inner(&mut self, at: &ast::Attribute, features: &Features) {
1039-
feature_gate::check_attribute(at, self.cx.parse_sess, features);
1040-
}
10411032
}
10421033

10431034
impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
@@ -1445,7 +1436,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
14451436

14461437
if let Some(file) = it.value_str() {
14471438
let err_count = self.cx.parse_sess.span_diagnostic.err_count();
1448-
self.check_attribute(&at);
1439+
self.check_attributes(slice::from_ref(at));
14491440
if self.cx.parse_sess.span_diagnostic.err_count() > err_count {
14501441
// avoid loading the file if they haven't enabled the feature
14511442
return noop_visit_attribute(at, self);

src/libsyntax/feature_gate/builtin_attrs.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ pub enum AttributeType {
7979
CrateLevel,
8080
}
8181

82+
#[derive(Clone, Copy)]
8283
pub enum AttributeGate {
8384
/// Is gated by a given feature gate, reason
8485
/// and function to check if enabled

src/libsyntax/feature_gate/check.rs

Lines changed: 40 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use super::{active::{ACTIVE_FEATURES, Features}, Feature, State as FeatureState};
22
use super::accepted::ACCEPTED_FEATURES;
33
use super::removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES};
4-
use super::builtin_attrs::{AttributeGate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
4+
use super::builtin_attrs::{AttributeGate, BUILTIN_ATTRIBUTE_MAP};
55

66
use crate::ast::{
77
self, AssocTyConstraint, AssocTyConstraintKind, NodeId, GenericParam, GenericParamKind,
@@ -61,40 +61,46 @@ macro_rules! gate_feature {
6161
};
6262
}
6363

64-
impl<'a> Context<'a> {
65-
fn check_attribute(
66-
&self,
67-
attr: &ast::Attribute,
68-
attr_info: Option<&BuiltinAttribute>,
69-
) {
70-
debug!("check_attribute(attr = {:?})", attr);
71-
if let Some(&(name, ty, _template, ref gateage)) = attr_info {
72-
if let AttributeGate::Gated(_, name, desc, ref has_feature) = *gateage {
73-
if !attr.span.allows_unstable(name) {
74-
gate_feature_fn!(
75-
self, has_feature, attr.span, name, desc, GateStrength::Hard
76-
);
77-
}
78-
} else if name == sym::doc {
79-
if let Some(content) = attr.meta_item_list() {
80-
if content.iter().any(|c| c.check_name(sym::include)) {
81-
gate_feature!(self, external_doc, attr.span,
82-
"`#[doc(include = \"...\")]` is experimental"
83-
);
84-
}
85-
}
64+
crate fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) {
65+
let cx = &Context { parse_sess, features };
66+
let attr_info =
67+
attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).map(|a| **a);
68+
// Check feature gates for built-in attributes.
69+
if let Some((.., AttributeGate::Gated(_, name, descr, has_feature))) = attr_info {
70+
gate_feature_fn!(cx, has_feature, attr.span, name, descr, GateStrength::Hard);
71+
}
72+
// Check input tokens for built-in and key-value attributes.
73+
match attr_info {
74+
// `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
75+
Some((name, _, template, _)) if name != sym::rustc_dummy =>
76+
check_builtin_attribute(parse_sess, attr, name, template),
77+
_ => if let Some(TokenTree::Token(token)) = attr.tokens.trees().next() {
78+
if token == token::Eq {
79+
// All key-value attributes are restricted to meta-item syntax.
80+
attr.parse_meta(parse_sess).map_err(|mut err| err.emit()).ok();
8681
}
87-
debug!("check_attribute: {:?} is builtin, {:?}, {:?}", attr.path, ty, gateage);
8882
}
8983
}
90-
}
91-
92-
pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) {
93-
let cx = Context { parse_sess, features };
94-
cx.check_attribute(
95-
attr,
96-
attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name).map(|a| *a)),
97-
);
84+
// Check unstable flavors of the `#[doc]` attribute.
85+
if attr.check_name(sym::doc) {
86+
for nested_meta in attr.meta_item_list().unwrap_or_default() {
87+
macro_rules! gate_doc { ($($name:ident => $feature:ident)*) => {
88+
$(if nested_meta.check_name(sym::$name) {
89+
let msg = concat!("`#[doc(", stringify!($name), ")]` is experimental");
90+
gate_feature!(cx, $feature, attr.span, msg);
91+
})*
92+
}}
93+
94+
gate_doc!(
95+
include => external_doc
96+
cfg => doc_cfg
97+
masked => doc_masked
98+
spotlight => doc_spotlight
99+
alias => doc_alias
100+
keyword => doc_keyword
101+
);
102+
}
103+
}
98104
}
99105

100106
fn find_lang_feature_issue(feature: Symbol) -> Option<u32> {
@@ -210,7 +216,6 @@ pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &str =
210216

211217
struct PostExpansionVisitor<'a> {
212218
context: &'a Context<'a>,
213-
builtin_attributes: &'static FxHashMap<Symbol, &'static BuiltinAttribute>,
214219
}
215220

216221
macro_rules! gate_feature_post {
@@ -287,50 +292,7 @@ impl<'a> PostExpansionVisitor<'a> {
287292

288293
impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
289294
fn visit_attribute(&mut self, attr: &ast::Attribute) {
290-
let attr_info = attr.ident().and_then(|ident| {
291-
self.builtin_attributes.get(&ident.name).map(|a| *a)
292-
});
293-
294-
// Check for gated attributes.
295-
self.context.check_attribute(attr, attr_info);
296-
297-
if attr.check_name(sym::doc) {
298-
if let Some(content) = attr.meta_item_list() {
299-
if content.len() == 1 && content[0].check_name(sym::cfg) {
300-
gate_feature_post!(&self, doc_cfg, attr.span,
301-
"`#[doc(cfg(...))]` is experimental"
302-
);
303-
} else if content.iter().any(|c| c.check_name(sym::masked)) {
304-
gate_feature_post!(&self, doc_masked, attr.span,
305-
"`#[doc(masked)]` is experimental"
306-
);
307-
} else if content.iter().any(|c| c.check_name(sym::spotlight)) {
308-
gate_feature_post!(&self, doc_spotlight, attr.span,
309-
"`#[doc(spotlight)]` is experimental"
310-
);
311-
} else if content.iter().any(|c| c.check_name(sym::alias)) {
312-
gate_feature_post!(&self, doc_alias, attr.span,
313-
"`#[doc(alias = \"...\")]` is experimental"
314-
);
315-
} else if content.iter().any(|c| c.check_name(sym::keyword)) {
316-
gate_feature_post!(&self, doc_keyword, attr.span,
317-
"`#[doc(keyword = \"...\")]` is experimental"
318-
);
319-
}
320-
}
321-
}
322-
323-
match attr_info {
324-
// `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
325-
Some(&(name, _, template, _)) if name != sym::rustc_dummy =>
326-
check_builtin_attribute(self.context.parse_sess, attr, name, template),
327-
_ => if let Some(TokenTree::Token(token)) = attr.tokens.trees().next() {
328-
if token == token::Eq {
329-
// All key-value attributes are restricted to meta-item syntax.
330-
attr.parse_meta(self.context.parse_sess).map_err(|mut err| err.emit()).ok();
331-
}
332-
}
333-
}
295+
check_attribute(attr, self.context.parse_sess, self.context.features);
334296
}
335297

336298
fn visit_name(&mut self, sp: Span, name: ast::Name) {
@@ -864,11 +826,7 @@ pub fn check_crate(krate: &ast::Crate,
864826
gate_all!(yields, generators, "yield syntax is experimental");
865827
gate_all!(or_patterns, "or-patterns syntax is experimental");
866828

867-
let visitor = &mut PostExpansionVisitor {
868-
context: &ctx,
869-
builtin_attributes: &*BUILTIN_ATTRIBUTE_MAP,
870-
};
871-
visit::walk_crate(visitor, krate);
829+
visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate);
872830
}
873831

874832
#[derive(Clone, Copy, Hash)]

src/libsyntax/feature_gate/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ pub use builtin_attrs::{
5858
deprecated_attributes, is_builtin_attr, is_builtin_attr_name,
5959
};
6060
pub use check::{
61-
check_attribute, check_crate, get_features, feature_err, emit_feature_err,
61+
check_crate, get_features, feature_err, emit_feature_err,
6262
Stability, GateIssue, UnstableFeatures,
6363
EXPLAIN_STMT_ATTR_SYNTAX, EXPLAIN_UNSIZED_TUPLE_COERCION,
6464
};
65+
crate use check::check_attribute;
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#[doc(alias = "foo")] //~ ERROR: `#[doc(alias = "...")]` is experimental
1+
#[doc(alias = "foo")] //~ ERROR: `#[doc(alias)]` is experimental
22
pub struct Foo;
33

44
fn main() {}

src/test/ui/feature-gates/feature-gate-doc_alias.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0658]: `#[doc(alias = "...")]` is experimental
1+
error[E0658]: `#[doc(alias)]` is experimental
22
--> $DIR/feature-gate-doc_alias.rs:1:1
33
|
44
LL | #[doc(alias = "foo")]
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
#[doc(cfg(unix))] //~ ERROR: `#[doc(cfg(...))]` is experimental
1+
#[doc(cfg(unix))] //~ ERROR: `#[doc(cfg)]` is experimental
22
fn main() {}

src/test/ui/feature-gates/feature-gate-doc_cfg.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0658]: `#[doc(cfg(...))]` is experimental
1+
error[E0658]: `#[doc(cfg)]` is experimental
22
--> $DIR/feature-gate-doc_cfg.rs:1:1
33
|
44
LL | #[doc(cfg(unix))]

src/test/ui/feature-gates/feature-gate-doc_keyword.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#[doc(keyword = "match")] //~ ERROR: `#[doc(keyword = "...")]` is experimental
1+
#[doc(keyword = "match")] //~ ERROR: `#[doc(keyword)]` is experimental
22
/// wonderful
33
mod foo{}
44

src/test/ui/feature-gates/feature-gate-doc_keyword.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0658]: `#[doc(keyword = "...")]` is experimental
1+
error[E0658]: `#[doc(keyword)]` is experimental
22
--> $DIR/feature-gate-doc_keyword.rs:1:1
33
|
44
LL | #[doc(keyword = "match")]
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
#[doc(include="asdf.md")] //~ ERROR: `#[doc(include = "...")]` is experimental
1+
#[doc(include="asdf.md")] //~ ERROR: `#[doc(include)]` is experimental
22
fn main() {}

src/test/ui/feature-gates/feature-gate-external_doc.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0658]: `#[doc(include = "...")]` is experimental
1+
error[E0658]: `#[doc(include)]` is experimental
22
--> $DIR/feature-gate-external_doc.rs:1:1
33
|
44
LL | #[doc(include="asdf.md")]

0 commit comments

Comments
 (0)