diff options
| author | Mazdak Farrokhzad <twingoow@gmail.com> | 2019-10-11 21:00:09 +0200 |
|---|---|---|
| committer | Mazdak Farrokhzad <twingoow@gmail.com> | 2019-11-09 02:04:24 +0100 |
| commit | 5011ec7fedffe34d943654ffb4308875fc5ec8f3 (patch) | |
| tree | e3fd7fb355643dd09c242a1020ad0eae9580d974 /src/libsyntax | |
| parent | 9e346646e93cc243567e27bb0f4e8716d56ad1f1 (diff) | |
| download | rust-5011ec7fedffe34d943654ffb4308875fc5ec8f3.tar.gz rust-5011ec7fedffe34d943654ffb4308875fc5ec8f3.zip | |
move attr meta grammar to parse::validate_atr + ast_validation
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/attr/builtin.rs | 69 | ||||
| -rw-r--r-- | src/libsyntax/attr/mod.rs | 19 | ||||
| -rw-r--r-- | src/libsyntax/config.rs | 4 | ||||
| -rw-r--r-- | src/libsyntax/feature_gate/check.rs | 23 | ||||
| -rw-r--r-- | src/libsyntax/parse/mod.rs | 1 | ||||
| -rw-r--r-- | src/libsyntax/parse/validate_attr.rs | 112 |
6 files changed, 119 insertions, 109 deletions
diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs index 787d69f5e99..3ac9abb7223 100644 --- a/src/libsyntax/attr/builtin.rs +++ b/src/libsyntax/attr/builtin.rs @@ -1,7 +1,6 @@ //! Parsing and validation of builtin attributes use crate::ast::{self, Attribute, MetaItem, NestedMetaItem}; -use crate::early_buffered_lints::BufferedEarlyLintId; use crate::feature_gate::{Features, GatedCfg}; use crate::print::pprust; use crate::sess::ParseSess; @@ -36,7 +35,7 @@ impl AttributeTemplate { } /// Checks that the given meta-item is compatible with this template. - fn compatible(&self, meta_item_kind: &ast::MetaItemKind) -> bool { + pub fn compatible(&self, meta_item_kind: &ast::MetaItemKind) -> bool { match meta_item_kind { ast::MetaItemKind::Word => self.word, ast::MetaItemKind::List(..) => self.list.is_some(), @@ -938,69 +937,3 @@ pub fn find_transparency( let fallback = if is_legacy { Transparency::SemiTransparent } else { Transparency::Opaque }; (transparency.map_or(fallback, |t| t.0), error) } - -pub fn check_builtin_attribute( - sess: &ParseSess, attr: &ast::Attribute, name: Symbol, template: AttributeTemplate -) { - // Some special attributes like `cfg` must be checked - // before the generic check, so we skip them here. - let should_skip = |name| name == sym::cfg; - // Some of previously accepted forms were used in practice, - // report them as warnings for now. - let should_warn = |name| name == sym::doc || name == sym::ignore || - name == sym::inline || name == sym::link || - name == sym::test || name == sym::bench; - - match attr.parse_meta(sess) { - Ok(meta) => if !should_skip(name) && !template.compatible(&meta.kind) { - let error_msg = format!("malformed `{}` attribute input", name); - let mut msg = "attribute must be of the form ".to_owned(); - let mut suggestions = vec![]; - let mut first = true; - if template.word { - first = false; - let code = format!("#[{}]", name); - msg.push_str(&format!("`{}`", &code)); - suggestions.push(code); - } - if let Some(descr) = template.list { - if !first { - msg.push_str(" or "); - } - first = false; - let code = format!("#[{}({})]", name, descr); - msg.push_str(&format!("`{}`", &code)); - suggestions.push(code); - } - if let Some(descr) = template.name_value_str { - if !first { - msg.push_str(" or "); - } - let code = format!("#[{} = \"{}\"]", name, descr); - msg.push_str(&format!("`{}`", &code)); - suggestions.push(code); - } - if should_warn(name) { - sess.buffer_lint( - BufferedEarlyLintId::IllFormedAttributeInput, - meta.span, - ast::CRATE_NODE_ID, - &msg, - ); - } else { - sess.span_diagnostic.struct_span_err(meta.span, &error_msg) - .span_suggestions( - meta.span, - if suggestions.len() == 1 { - "must be of the form" - } else { - "the following are the possible correct uses" - }, - suggestions.into_iter(), - Applicability::HasPlaceholders, - ).emit(); - } - } - Err(mut err) => err.emit(), - } -} diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index c639431794c..2c011b06470 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -14,17 +14,13 @@ use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem}; use crate::ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind, GenericParam}; use crate::mut_visit::visit_clobber; use crate::source_map::{BytePos, Spanned}; -use crate::parse; use crate::token::{self, Token}; use crate::ptr::P; -use crate::sess::ParseSess; use crate::symbol::{sym, Symbol}; use crate::ThinVec; use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint}; use crate::GLOBALS; -use errors::PResult; - use log::debug; use syntax_pos::Span; @@ -328,21 +324,6 @@ impl Attribute { Some(mk_name_value_item_str(Ident::new(sym::doc, self.span), comment, self.span)), } } - - pub fn parse_meta<'a>(&self, sess: &'a ParseSess) -> PResult<'a, MetaItem> { - match self.kind { - AttrKind::Normal(ref item) => { - Ok(MetaItem { - path: item.path.clone(), - kind: parse::parse_in_attr(sess, self, |parser| parser.parse_meta_item_kind())?, - span: self.span, - }) - } - AttrKind::DocComment(comment) => { - Ok(mk_name_value_item_str(Ident::new(sym::doc, self.span), comment, self.span)) - } - } - } } /* Constructors */ diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 5f89ed36e2a..a460fc2b99a 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -10,7 +10,7 @@ use crate::attr; use crate::ast; use crate::edition::Edition; use crate::mut_visit::*; -use crate::parse; +use crate::parse::{self, validate_attr}; use crate::ptr::P; use crate::sess::ParseSess; use crate::symbol::sym; @@ -168,7 +168,7 @@ impl<'a> StripUnconfigured<'a> { true }; - let meta_item = match attr.parse_meta(self.sess) { + let meta_item = match validate_attr::parse_meta(self.sess, attr) { Ok(meta_item) => meta_item, Err(mut err) => { err.emit(); return true; } }; diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index ecff89ad59b..4742e01d7f4 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -3,18 +3,14 @@ use super::accepted::ACCEPTED_FEATURES; use super::removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES}; use super::builtin_attrs::{AttributeGate, BUILTIN_ATTRIBUTE_MAP}; -use crate::ast::{ - self, AssocTyConstraint, AssocTyConstraintKind, NodeId, GenericParam, GenericParamKind, - PatKind, RangeEnd, VariantData, -}; -use crate::attr::{self, check_builtin_attribute}; +use crate::ast::{self, AssocTyConstraint, AssocTyConstraintKind, NodeId}; +use crate::ast::{GenericParam, GenericParamKind, PatKind, RangeEnd, VariantData}; +use crate::attr; use crate::source_map::Spanned; use crate::edition::{ALL_EDITIONS, Edition}; use crate::visit::{self, FnKind, Visitor}; -use crate::token; use crate::sess::ParseSess; use crate::symbol::{Symbol, sym}; -use crate::tokenstream::TokenTree; use errors::{Applicability, DiagnosticBuilder, Handler}; use rustc_data_structures::fx::FxHashMap; @@ -331,19 +327,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { if let Some((.., AttributeGate::Gated(_, name, descr, has_feature))) = attr_info { gate_feature_fn!(self, has_feature, attr.span, name, descr, GateStrength::Hard); } - // Check input tokens for built-in and key-value attributes. - match attr_info { - // `rustc_dummy` doesn't have any restrictions specific to built-in attributes. - Some((name, _, template, _)) if name != sym::rustc_dummy => - check_builtin_attribute(self.parse_sess, attr, name, template), - _ => if let Some(TokenTree::Token(token)) = - attr.get_normal_item().tokens.trees().next() { - if token == token::Eq { - // All key-value attributes are restricted to meta-item syntax. - attr.parse_meta(self.parse_sess).map_err(|mut err| err.emit()).ok(); - } - } - } // Check unstable flavors of the `#[doc]` attribute. if attr.check_name(sym::doc) { for nested_meta in attr.meta_item_list().unwrap_or_default() { diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index b54f4862f12..9155cbe5dd8 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -23,6 +23,7 @@ mod tests; #[macro_use] pub mod parser; pub mod lexer; +pub mod validate_attr; #[derive(Clone)] pub struct Directory<'a> { diff --git a/src/libsyntax/parse/validate_attr.rs b/src/libsyntax/parse/validate_attr.rs new file mode 100644 index 00000000000..6cc8a1ec33e --- /dev/null +++ b/src/libsyntax/parse/validate_attr.rs @@ -0,0 +1,112 @@ +//! Meta-syntax validation logic of attributes for post-expansion. + +use crate::ast::{self, Attribute, AttrKind, Ident, MetaItem}; +use crate::attr::{AttributeTemplate, mk_name_value_item_str}; +use crate::sess::ParseSess; +use crate::feature_gate::BUILTIN_ATTRIBUTE_MAP; +use crate::early_buffered_lints::BufferedEarlyLintId; +use crate::token; +use crate::tokenstream::TokenTree; + +use errors::{PResult, Applicability}; +use syntax_pos::{Symbol, sym}; + +pub fn check_meta(sess: &ParseSess, attr: &Attribute) { + let attr_info = + attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).map(|a| **a); + + // Check input tokens for built-in and key-value attributes. + match attr_info { + // `rustc_dummy` doesn't have any restrictions specific to built-in attributes. + Some((name, _, template, _)) if name != sym::rustc_dummy => + check_builtin_attribute(sess, attr, name, template), + _ => if let Some(TokenTree::Token(token)) = attr.get_normal_item().tokens.trees().next() { + if token == token::Eq { + // All key-value attributes are restricted to meta-item syntax. + parse_meta(sess, attr).map_err(|mut err| err.emit()).ok(); + } + } + } +} + +pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, MetaItem> { + Ok(match attr.kind { + AttrKind::Normal(ref item) => MetaItem { + path: item.path.clone(), + kind: super::parse_in_attr(sess, attr, |p| p.parse_meta_item_kind())?, + span: attr.span, + }, + AttrKind::DocComment(comment) => { + mk_name_value_item_str(Ident::new(sym::doc, attr.span), comment, attr.span) + } + }) +} + +pub fn check_builtin_attribute( + sess: &ParseSess, + attr: &Attribute, + name: Symbol, + template: AttributeTemplate, +) { + // Some special attributes like `cfg` must be checked + // before the generic check, so we skip them here. + let should_skip = |name| name == sym::cfg; + // Some of previously accepted forms were used in practice, + // report them as warnings for now. + let should_warn = |name| name == sym::doc || name == sym::ignore || + name == sym::inline || name == sym::link || + name == sym::test || name == sym::bench; + + match parse_meta(sess, attr) { + Ok(meta) => if !should_skip(name) && !template.compatible(&meta.kind) { + let error_msg = format!("malformed `{}` attribute input", name); + let mut msg = "attribute must be of the form ".to_owned(); + let mut suggestions = vec![]; + let mut first = true; + if template.word { + first = false; + let code = format!("#[{}]", name); + msg.push_str(&format!("`{}`", &code)); + suggestions.push(code); + } + if let Some(descr) = template.list { + if !first { + msg.push_str(" or "); + } + first = false; + let code = format!("#[{}({})]", name, descr); + msg.push_str(&format!("`{}`", &code)); + suggestions.push(code); + } + if let Some(descr) = template.name_value_str { + if !first { + msg.push_str(" or "); + } + let code = format!("#[{} = \"{}\"]", name, descr); + msg.push_str(&format!("`{}`", &code)); + suggestions.push(code); + } + if should_warn(name) { + sess.buffer_lint( + BufferedEarlyLintId::IllFormedAttributeInput, + meta.span, + ast::CRATE_NODE_ID, + &msg, + ); + } else { + sess.span_diagnostic.struct_span_err(meta.span, &error_msg) + .span_suggestions( + meta.span, + if suggestions.len() == 1 { + "must be of the form" + } else { + "the following are the possible correct uses" + }, + suggestions.into_iter(), + Applicability::HasPlaceholders, + ).emit(); + } + } + Err(mut err) => err.emit(), + } +} |
