diff options
Diffstat (limited to 'compiler/rustc_parse/src/validate_attr.rs')
-rw-r--r-- | compiler/rustc_parse/src/validate_attr.rs | 68 |
1 files changed, 40 insertions, 28 deletions
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 47477898b..72402a200 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -3,15 +3,16 @@ use crate::parse_in; use rustc_ast::tokenstream::DelimSpan; -use rustc_ast::{self as ast, Attribute, MacArgs, MacArgsEq, MacDelimiter, MetaItem, MetaItemKind}; +use rustc_ast::MetaItemKind; +use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, Attribute, DelimArgs, MacDelimiter, MetaItem}; use rustc_ast_pretty::pprust; use rustc_errors::{Applicability, FatalError, PResult}; use rustc_feature::{AttributeTemplate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT; use rustc_session::parse::ParseSess; -use rustc_span::{sym, Symbol}; +use rustc_span::{sym, Span, Symbol}; -pub fn check_meta(sess: &ParseSess, attr: &Attribute) { +pub fn check_attr(sess: &ParseSess, attr: &Attribute) { if attr.is_doc_comment() { return; } @@ -24,7 +25,7 @@ pub fn check_meta(sess: &ParseSess, attr: &Attribute) { Some(BuiltinAttribute { name, template, .. }) if *name != sym::rustc_dummy => { check_builtin_attribute(sess, attr, *name, *template) } - _ if let MacArgs::Eq(..) = attr.get_normal_item().args => { + _ if let AttrArgs::Eq(..) = attr.get_normal_item().args => { // All key-value attributes are restricted to meta-item syntax. parse_meta(sess, attr) .map_err(|mut err| { @@ -42,17 +43,19 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta span: attr.span, path: item.path.clone(), kind: match &item.args { - MacArgs::Empty => MetaItemKind::Word, - MacArgs::Delimited(dspan, delim, t) => { + AttrArgs::Empty => MetaItemKind::Word, + AttrArgs::Delimited(DelimArgs { dspan, delim, tokens }) => { check_meta_bad_delim(sess, *dspan, *delim, "wrong meta list delimiters"); - let nmis = parse_in(sess, t.clone(), "meta list", |p| p.parse_meta_seq_top())?; + let nmis = parse_in(sess, tokens.clone(), "meta list", |p| p.parse_meta_seq_top())?; MetaItemKind::List(nmis) } - MacArgs::Eq(_, MacArgsEq::Ast(expr)) => { - if let ast::ExprKind::Lit(lit) = &expr.kind { - if !lit.kind.is_unsuffixed() { + AttrArgs::Eq(_, AttrArgsEq::Ast(expr)) => { + if let ast::ExprKind::Lit(token_lit) = expr.kind + && let Ok(lit) = ast::MetaItemLit::from_token_lit(token_lit, expr.span) + { + if token_lit.suffix.is_some() { let mut err = sess.span_diagnostic.struct_span_err( - lit.span, + expr.span, "suffixed literals are not allowed in attributes", ); err.help( @@ -61,7 +64,7 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta ); return Err(err); } else { - MetaItemKind::NameValue(lit.clone()) + MetaItemKind::NameValue(lit) } } else { // The non-error case can happen with e.g. `#[foo = 1+1]`. The error case can @@ -76,7 +79,7 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta return Err(err); } } - MacArgs::Eq(_, MacArgsEq::Hir(lit)) => MetaItemKind::NameValue(lit.clone()), + AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => MetaItemKind::NameValue(lit.clone()), }, }) } @@ -112,25 +115,34 @@ pub fn check_builtin_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; - match parse_meta(sess, attr) { - Ok(meta) => { - if !should_skip(name) && !is_attr_template_compatible(&template, &meta.kind) { - emit_malformed_attribute(sess, attr, name, template); - } - } + Ok(meta) => check_builtin_meta_item(sess, &meta, attr.style, name, template), Err(mut err) => { err.emit(); } } } +pub fn check_builtin_meta_item( + sess: &ParseSess, + meta: &MetaItem, + style: ast::AttrStyle, + 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; + + if !should_skip(name) && !is_attr_template_compatible(&template, &meta.kind) { + emit_malformed_attribute(sess, style, meta.span, name, template); + } +} + fn emit_malformed_attribute( sess: &ParseSess, - attr: &Attribute, + style: ast::AttrStyle, + span: Span, name: Symbol, template: AttributeTemplate, ) { @@ -144,7 +156,7 @@ fn emit_malformed_attribute( let mut msg = "attribute must be of the form ".to_owned(); let mut suggestions = vec![]; let mut first = true; - let inner = if attr.style == ast::AttrStyle::Inner { "!" } else { "" }; + let inner = if style == ast::AttrStyle::Inner { "!" } else { "" }; if template.word { first = false; let code = format!("#{}[{}]", inner, name); @@ -169,12 +181,12 @@ fn emit_malformed_attribute( suggestions.push(code); } if should_warn(name) { - sess.buffer_lint(&ILL_FORMED_ATTRIBUTE_INPUT, attr.span, ast::CRATE_NODE_ID, &msg); + sess.buffer_lint(&ILL_FORMED_ATTRIBUTE_INPUT, span, ast::CRATE_NODE_ID, &msg); } else { sess.span_diagnostic - .struct_span_err(attr.span, &error_msg) + .struct_span_err(span, &error_msg) .span_suggestions( - attr.span, + span, if suggestions.len() == 1 { "must be of the form" } else { @@ -193,7 +205,7 @@ pub fn emit_fatal_malformed_builtin_attribute( name: Symbol, ) -> ! { let template = BUILTIN_ATTRIBUTE_MAP.get(&name).expect("builtin attr defined").template; - emit_malformed_attribute(sess, attr, name, template); + emit_malformed_attribute(sess, attr.style, attr.span, name, template); // This is fatal, otherwise it will likely cause a cascade of other errors // (and an error here is expected to be very rare). FatalError.raise() |