Skip to content

Commit 5011ec7

Browse files
committed
move attr meta grammar to parse::validate_atr + ast_validation
1 parent 9e34664 commit 5011ec7

File tree

10 files changed

+142
-124
lines changed

10 files changed

+142
-124
lines changed

src/librustc_passes/ast_validation.rs

+5
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use syntax::ast::*;
1515
use syntax::attr;
1616
use syntax::expand::is_proc_macro_attr;
1717
use syntax::feature_gate::is_builtin_attr;
18+
use syntax::parse::validate_attr;
1819
use syntax::source_map::Spanned;
1920
use syntax::symbol::{kw, sym};
2021
use syntax::visit::{self, Visitor};
@@ -369,6 +370,10 @@ fn validate_generics_order<'a>(
369370
}
370371

371372
impl<'a> Visitor<'a> for AstValidator<'a> {
373+
fn visit_attribute(&mut self, attr: &Attribute) {
374+
validate_attr::check_meta(&self.session.parse_sess, attr);
375+
}
376+
372377
fn visit_expr(&mut self, expr: &'a Expr) {
373378
match &expr.kind {
374379
ExprKind::Closure(_, _, _, fn_decl, _, _) => {

src/libsyntax/attr/builtin.rs

+1-68
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
//! Parsing and validation of builtin attributes
22
33
use crate::ast::{self, Attribute, MetaItem, NestedMetaItem};
4-
use crate::early_buffered_lints::BufferedEarlyLintId;
54
use crate::feature_gate::{Features, GatedCfg};
65
use crate::print::pprust;
76
use crate::sess::ParseSess;
@@ -36,7 +35,7 @@ impl AttributeTemplate {
3635
}
3736

3837
/// Checks that the given meta-item is compatible with this template.
39-
fn compatible(&self, meta_item_kind: &ast::MetaItemKind) -> bool {
38+
pub fn compatible(&self, meta_item_kind: &ast::MetaItemKind) -> bool {
4039
match meta_item_kind {
4140
ast::MetaItemKind::Word => self.word,
4241
ast::MetaItemKind::List(..) => self.list.is_some(),
@@ -938,69 +937,3 @@ pub fn find_transparency(
938937
let fallback = if is_legacy { Transparency::SemiTransparent } else { Transparency::Opaque };
939938
(transparency.map_or(fallback, |t| t.0), error)
940939
}
941-
942-
pub fn check_builtin_attribute(
943-
sess: &ParseSess, attr: &ast::Attribute, name: Symbol, template: AttributeTemplate
944-
) {
945-
// Some special attributes like `cfg` must be checked
946-
// before the generic check, so we skip them here.
947-
let should_skip = |name| name == sym::cfg;
948-
// Some of previously accepted forms were used in practice,
949-
// report them as warnings for now.
950-
let should_warn = |name| name == sym::doc || name == sym::ignore ||
951-
name == sym::inline || name == sym::link ||
952-
name == sym::test || name == sym::bench;
953-
954-
match attr.parse_meta(sess) {
955-
Ok(meta) => if !should_skip(name) && !template.compatible(&meta.kind) {
956-
let error_msg = format!("malformed `{}` attribute input", name);
957-
let mut msg = "attribute must be of the form ".to_owned();
958-
let mut suggestions = vec![];
959-
let mut first = true;
960-
if template.word {
961-
first = false;
962-
let code = format!("#[{}]", name);
963-
msg.push_str(&format!("`{}`", &code));
964-
suggestions.push(code);
965-
}
966-
if let Some(descr) = template.list {
967-
if !first {
968-
msg.push_str(" or ");
969-
}
970-
first = false;
971-
let code = format!("#[{}({})]", name, descr);
972-
msg.push_str(&format!("`{}`", &code));
973-
suggestions.push(code);
974-
}
975-
if let Some(descr) = template.name_value_str {
976-
if !first {
977-
msg.push_str(" or ");
978-
}
979-
let code = format!("#[{} = \"{}\"]", name, descr);
980-
msg.push_str(&format!("`{}`", &code));
981-
suggestions.push(code);
982-
}
983-
if should_warn(name) {
984-
sess.buffer_lint(
985-
BufferedEarlyLintId::IllFormedAttributeInput,
986-
meta.span,
987-
ast::CRATE_NODE_ID,
988-
&msg,
989-
);
990-
} else {
991-
sess.span_diagnostic.struct_span_err(meta.span, &error_msg)
992-
.span_suggestions(
993-
meta.span,
994-
if suggestions.len() == 1 {
995-
"must be of the form"
996-
} else {
997-
"the following are the possible correct uses"
998-
},
999-
suggestions.into_iter(),
1000-
Applicability::HasPlaceholders,
1001-
).emit();
1002-
}
1003-
}
1004-
Err(mut err) => err.emit(),
1005-
}
1006-
}

src/libsyntax/attr/mod.rs

-19
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,13 @@ use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem};
1414
use crate::ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind, GenericParam};
1515
use crate::mut_visit::visit_clobber;
1616
use crate::source_map::{BytePos, Spanned};
17-
use crate::parse;
1817
use crate::token::{self, Token};
1918
use crate::ptr::P;
20-
use crate::sess::ParseSess;
2119
use crate::symbol::{sym, Symbol};
2220
use crate::ThinVec;
2321
use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint};
2422
use crate::GLOBALS;
2523

26-
use errors::PResult;
27-
2824
use log::debug;
2925
use syntax_pos::Span;
3026

@@ -328,21 +324,6 @@ impl Attribute {
328324
Some(mk_name_value_item_str(Ident::new(sym::doc, self.span), comment, self.span)),
329325
}
330326
}
331-
332-
pub fn parse_meta<'a>(&self, sess: &'a ParseSess) -> PResult<'a, MetaItem> {
333-
match self.kind {
334-
AttrKind::Normal(ref item) => {
335-
Ok(MetaItem {
336-
path: item.path.clone(),
337-
kind: parse::parse_in_attr(sess, self, |parser| parser.parse_meta_item_kind())?,
338-
span: self.span,
339-
})
340-
}
341-
AttrKind::DocComment(comment) => {
342-
Ok(mk_name_value_item_str(Ident::new(sym::doc, self.span), comment, self.span))
343-
}
344-
}
345-
}
346327
}
347328

348329
/* Constructors */

src/libsyntax/config.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::attr;
1010
use crate::ast;
1111
use crate::edition::Edition;
1212
use crate::mut_visit::*;
13-
use crate::parse;
13+
use crate::parse::{self, validate_attr};
1414
use crate::ptr::P;
1515
use crate::sess::ParseSess;
1616
use crate::symbol::sym;
@@ -168,7 +168,7 @@ impl<'a> StripUnconfigured<'a> {
168168
true
169169
};
170170

171-
let meta_item = match attr.parse_meta(self.sess) {
171+
let meta_item = match validate_attr::parse_meta(self.sess, attr) {
172172
Ok(meta_item) => meta_item,
173173
Err(mut err) => { err.emit(); return true; }
174174
};

src/libsyntax/feature_gate/check.rs

+3-20
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,14 @@ use super::accepted::ACCEPTED_FEATURES;
33
use super::removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES};
44
use super::builtin_attrs::{AttributeGate, BUILTIN_ATTRIBUTE_MAP};
55

6-
use crate::ast::{
7-
self, AssocTyConstraint, AssocTyConstraintKind, NodeId, GenericParam, GenericParamKind,
8-
PatKind, RangeEnd, VariantData,
9-
};
10-
use crate::attr::{self, check_builtin_attribute};
6+
use crate::ast::{self, AssocTyConstraint, AssocTyConstraintKind, NodeId};
7+
use crate::ast::{GenericParam, GenericParamKind, PatKind, RangeEnd, VariantData};
8+
use crate::attr;
119
use crate::source_map::Spanned;
1210
use crate::edition::{ALL_EDITIONS, Edition};
1311
use crate::visit::{self, FnKind, Visitor};
14-
use crate::token;
1512
use crate::sess::ParseSess;
1613
use crate::symbol::{Symbol, sym};
17-
use crate::tokenstream::TokenTree;
1814

1915
use errors::{Applicability, DiagnosticBuilder, Handler};
2016
use rustc_data_structures::fx::FxHashMap;
@@ -331,19 +327,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
331327
if let Some((.., AttributeGate::Gated(_, name, descr, has_feature))) = attr_info {
332328
gate_feature_fn!(self, has_feature, attr.span, name, descr, GateStrength::Hard);
333329
}
334-
// Check input tokens for built-in and key-value attributes.
335-
match attr_info {
336-
// `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
337-
Some((name, _, template, _)) if name != sym::rustc_dummy =>
338-
check_builtin_attribute(self.parse_sess, attr, name, template),
339-
_ => if let Some(TokenTree::Token(token)) =
340-
attr.get_normal_item().tokens.trees().next() {
341-
if token == token::Eq {
342-
// All key-value attributes are restricted to meta-item syntax.
343-
attr.parse_meta(self.parse_sess).map_err(|mut err| err.emit()).ok();
344-
}
345-
}
346-
}
347330
// Check unstable flavors of the `#[doc]` attribute.
348331
if attr.check_name(sym::doc) {
349332
for nested_meta in attr.meta_item_list().unwrap_or_default() {

src/libsyntax/parse/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ mod tests;
2323
#[macro_use]
2424
pub mod parser;
2525
pub mod lexer;
26+
pub mod validate_attr;
2627

2728
#[derive(Clone)]
2829
pub struct Directory<'a> {

src/libsyntax/parse/validate_attr.rs

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
//! Meta-syntax validation logic of attributes for post-expansion.
2+
3+
use crate::ast::{self, Attribute, AttrKind, Ident, MetaItem};
4+
use crate::attr::{AttributeTemplate, mk_name_value_item_str};
5+
use crate::sess::ParseSess;
6+
use crate::feature_gate::BUILTIN_ATTRIBUTE_MAP;
7+
use crate::early_buffered_lints::BufferedEarlyLintId;
8+
use crate::token;
9+
use crate::tokenstream::TokenTree;
10+
11+
use errors::{PResult, Applicability};
12+
use syntax_pos::{Symbol, sym};
13+
14+
pub fn check_meta(sess: &ParseSess, attr: &Attribute) {
15+
let attr_info =
16+
attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).map(|a| **a);
17+
18+
// Check input tokens for built-in and key-value attributes.
19+
match attr_info {
20+
// `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
21+
Some((name, _, template, _)) if name != sym::rustc_dummy =>
22+
check_builtin_attribute(sess, attr, name, template),
23+
_ => if let Some(TokenTree::Token(token)) = attr.get_normal_item().tokens.trees().next() {
24+
if token == token::Eq {
25+
// All key-value attributes are restricted to meta-item syntax.
26+
parse_meta(sess, attr).map_err(|mut err| err.emit()).ok();
27+
}
28+
}
29+
}
30+
}
31+
32+
pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, MetaItem> {
33+
Ok(match attr.kind {
34+
AttrKind::Normal(ref item) => MetaItem {
35+
path: item.path.clone(),
36+
kind: super::parse_in_attr(sess, attr, |p| p.parse_meta_item_kind())?,
37+
span: attr.span,
38+
},
39+
AttrKind::DocComment(comment) => {
40+
mk_name_value_item_str(Ident::new(sym::doc, attr.span), comment, attr.span)
41+
}
42+
})
43+
}
44+
45+
pub fn check_builtin_attribute(
46+
sess: &ParseSess,
47+
attr: &Attribute,
48+
name: Symbol,
49+
template: AttributeTemplate,
50+
) {
51+
// Some special attributes like `cfg` must be checked
52+
// before the generic check, so we skip them here.
53+
let should_skip = |name| name == sym::cfg;
54+
// Some of previously accepted forms were used in practice,
55+
// report them as warnings for now.
56+
let should_warn = |name| name == sym::doc || name == sym::ignore ||
57+
name == sym::inline || name == sym::link ||
58+
name == sym::test || name == sym::bench;
59+
60+
match parse_meta(sess, attr) {
61+
Ok(meta) => if !should_skip(name) && !template.compatible(&meta.kind) {
62+
let error_msg = format!("malformed `{}` attribute input", name);
63+
let mut msg = "attribute must be of the form ".to_owned();
64+
let mut suggestions = vec![];
65+
let mut first = true;
66+
if template.word {
67+
first = false;
68+
let code = format!("#[{}]", name);
69+
msg.push_str(&format!("`{}`", &code));
70+
suggestions.push(code);
71+
}
72+
if let Some(descr) = template.list {
73+
if !first {
74+
msg.push_str(" or ");
75+
}
76+
first = false;
77+
let code = format!("#[{}({})]", name, descr);
78+
msg.push_str(&format!("`{}`", &code));
79+
suggestions.push(code);
80+
}
81+
if let Some(descr) = template.name_value_str {
82+
if !first {
83+
msg.push_str(" or ");
84+
}
85+
let code = format!("#[{} = \"{}\"]", name, descr);
86+
msg.push_str(&format!("`{}`", &code));
87+
suggestions.push(code);
88+
}
89+
if should_warn(name) {
90+
sess.buffer_lint(
91+
BufferedEarlyLintId::IllFormedAttributeInput,
92+
meta.span,
93+
ast::CRATE_NODE_ID,
94+
&msg,
95+
);
96+
} else {
97+
sess.span_diagnostic.struct_span_err(meta.span, &error_msg)
98+
.span_suggestions(
99+
meta.span,
100+
if suggestions.len() == 1 {
101+
"must be of the form"
102+
} else {
103+
"the following are the possible correct uses"
104+
},
105+
suggestions.into_iter(),
106+
Applicability::HasPlaceholders,
107+
).emit();
108+
}
109+
}
110+
Err(mut err) => err.emit(),
111+
}
112+
}

src/libsyntax_expand/expand.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use syntax::feature_gate::{self, Features, GateIssue, is_builtin_attr, emit_feat
1414
use syntax::mut_visit::*;
1515
use syntax::parse::DirectoryOwnership;
1616
use syntax::parse::parser::Parser;
17+
use syntax::parse::validate_attr;
1718
use syntax::print::pprust;
1819
use syntax::ptr::P;
1920
use syntax::sess::ParseSess;
@@ -640,7 +641,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
640641
self.parse_ast_fragment(tok_result, fragment_kind, &item.path, span)
641642
}
642643
SyntaxExtensionKind::LegacyAttr(expander) => {
643-
match attr.parse_meta(self.cx.parse_sess) {
644+
match validate_attr::parse_meta(self.cx.parse_sess, &attr) {
644645
Ok(meta) => {
645646
let item = expander.expand(self.cx, span, &meta, item);
646647
fragment_kind.expect_from_annotatables(item)
@@ -1031,6 +1032,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
10311032
let features = self.cx.ecfg.features.unwrap();
10321033
for attr in attrs.iter() {
10331034
feature_gate::check_attribute(attr, self.cx.parse_sess, features);
1035+
validate_attr::check_meta(self.cx.parse_sess, attr);
10341036

10351037
// macros are expanded before any lint passes so this warning has to be hardcoded
10361038
if attr.has_name(sym::derive) {

src/libsyntax_ext/util.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
use syntax_pos::Symbol;
22
use syntax::ast::MetaItem;
3-
use syntax::attr::{check_builtin_attribute, AttributeTemplate};
3+
use syntax::attr::AttributeTemplate;
4+
use syntax::parse::validate_attr;
45
use syntax_expand::base::ExtCtxt;
56

67
pub fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, name: Symbol) {
78
// All the built-in macro attributes are "words" at the moment.
89
let template = AttributeTemplate::only_word();
910
let attr = ecx.attribute(meta_item.clone());
10-
check_builtin_attribute(ecx.parse_sess, &attr, name, template);
11+
validate_attr::check_builtin_attribute(ecx.parse_sess, &attr, name, template);
1112
}

0 commit comments

Comments
 (0)