use syntax::ast;
use syntax::ptr::P;
use syntax::ast::Expr;
-use syntax::attr::{self, HasAttrs};
+use syntax::attr::{self, HasAttrs, AttributeTemplate};
use syntax::source_map::Spanned;
use syntax::edition::Edition;
-use syntax::feature_gate::{AttributeGate, AttributeTemplate, AttributeType};
+use syntax::feature_gate::{AttributeGate, AttributeType};
use syntax::feature_gate::{Stability, deprecated_attributes};
use syntax_pos::{BytePos, Span, SyntaxContext};
use syntax::symbol::{Symbol, kw, sym};
//! Parsing and validation of builtin attributes
use crate::ast::{self, Attribute, MetaItem, NestedMetaItem};
+use crate::early_buffered_lints::BufferedEarlyLintId;
+use crate::ext::base::ExtCtxt;
+use crate::ext::build::AstBuilder;
use crate::feature_gate::{Features, GatedCfg};
use crate::parse::ParseSess;
UnsupportedLiteral(&'static str, /* is_bytestr */ bool),
}
+/// A template that the attribute input must match.
+/// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now.
+#[derive(Clone, Copy)]
+pub struct AttributeTemplate {
+ crate word: bool,
+ crate list: Option<&'static str>,
+ crate name_value_str: Option<&'static str>,
+}
+
+impl AttributeTemplate {
+ /// Checks that the given meta-item is compatible with this template.
+ 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(),
+ ast::MetaItemKind::NameValue(lit) if lit.node.is_str() => self.name_value_str.is_some(),
+ ast::MetaItemKind::NameValue(..) => false,
+ }
+ }
+}
+
fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) {
let diag = &sess.span_diagnostic;
match error {
let fallback = if is_legacy { Transparency::SemiTransparent } else { Transparency::Opaque };
(transparency.map_or(fallback, |t| t.0), error)
}
+
+pub fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, name: Symbol) {
+ // All the built-in macro attributes are "words" at the moment.
+ let template = AttributeTemplate { word: true, list: None, name_value_str: None };
+ let attr = ecx.attribute(meta_item.span, meta_item.clone());
+ check_builtin_attribute(ecx.parse_sess, &attr, name, template);
+}
+
+crate 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;
+
+ match attr.parse_meta(sess) {
+ Ok(meta) => if !should_skip(name) && !template.compatible(&meta.node) {
+ 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(),
+ }
+}
self, AssocTyConstraint, AssocTyConstraintKind, NodeId, GenericParam, GenericParamKind,
PatKind, RangeEnd,
};
-use crate::attr;
-use crate::early_buffered_lints::BufferedEarlyLintId;
+use crate::attr::{self, check_builtin_attribute, AttributeTemplate};
use crate::source_map::Spanned;
use crate::edition::{ALL_EDITIONS, Edition};
use crate::visit::{self, FnKind, Visitor};
Ungated,
}
-/// A template that the attribute input must match.
-/// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now.
-#[derive(Clone, Copy)]
-pub struct AttributeTemplate {
- word: bool,
- list: Option<&'static str>,
- name_value_str: Option<&'static str>,
-}
-
-impl AttributeTemplate {
- /// Checks that the given meta-item is compatible with this template.
- 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(),
- ast::MetaItemKind::NameValue(lit) if lit.node.is_str() => self.name_value_str.is_some(),
- ast::MetaItemKind::NameValue(..) => false,
- }
- }
-}
-
/// A convenience macro for constructing attribute templates.
/// E.g., `template!(Word, List: "description")` means that the attribute
/// supports forms `#[attr]` and `#[attr(description)]`.
Abi::System => {}
}
}
-
- fn check_builtin_attribute(&mut self, 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;
-
- match attr.parse_meta(self.context.parse_sess) {
- Ok(meta) => if !should_skip(name) && !template.compatible(&meta.node) {
- 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) {
- self.context.parse_sess.buffer_lint(
- BufferedEarlyLintId::IllFormedAttributeInput,
- meta.span,
- ast::CRATE_NODE_ID,
- &msg,
- );
- } else {
- self.context.parse_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(),
- }
- }
}
impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
match attr_info {
// `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
Some(&(name, _, template, _)) if name != sym::rustc_dummy =>
- self.check_builtin_attribute(attr, name, template),
+ check_builtin_attribute(self.context.parse_sess, attr, name, template),
_ => if let Some(TokenTree::Token(token)) = attr.tokens.trees().next() {
if token == token::Eq {
// All key-value attributes are restricted to meta-item syntax.
-use errors::Applicability;
-use syntax::ast::{self, Arg, Attribute, Expr, FnHeader, Generics, Ident, Item};
use syntax::ast::{ItemKind, Mutability, Ty, TyKind, Unsafety, VisibilityKind};
-use syntax::source_map::respan;
+use syntax::ast::{self, Arg, Attribute, Expr, FnHeader, Generics, Ident, Item};
+use syntax::attr::check_builtin_macro_attribute;
use syntax::ext::allocator::{AllocatorKind, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS};
use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::build::AstBuilder;
use syntax::ext::hygiene::SyntaxContext;
use syntax::ptr::P;
+use syntax::source_map::respan;
use syntax::symbol::{kw, sym};
use syntax_pos::Span;
pub fn expand(
ecx: &mut ExtCtxt<'_>,
- span: Span,
+ _span: Span,
meta_item: &ast::MetaItem,
item: Annotatable,
) -> Vec<Annotatable> {
- if !meta_item.is_word() {
- let msg = format!("malformed `{}` attribute input", meta_item.path);
- ecx.parse_sess.span_diagnostic.struct_span_err(span, &msg)
- .span_suggestion(
- span,
- "must be of the form",
- format!("`#[{}]`", meta_item.path),
- Applicability::MachineApplicable
- ).emit();
- }
+ check_builtin_macro_attribute(ecx, meta_item, sym::global_allocator);
let not_static = |item: Annotatable| {
ecx.parse_sess.span_diagnostic.span_err(item.span(), "allocators must be statics");
/// The expansion from a test function to the appropriate test struct for libtest
/// Ideally, this code would be in libtest but for efficiency and error messages it lives here.
+use syntax::ast;
+use syntax::attr::{self, check_builtin_macro_attribute};
use syntax::ext::base::*;
use syntax::ext::build::AstBuilder;
use syntax::ext::hygiene::SyntaxContext;
-use syntax::attr;
-use syntax::ast;
use syntax::print::pprust;
use syntax::symbol::{Symbol, sym};
use syntax_pos::Span;
+
use std::iter;
pub fn expand_test(
cx: &mut ExtCtxt<'_>,
attr_sp: Span,
- _meta_item: &ast::MetaItem,
+ meta_item: &ast::MetaItem,
item: Annotatable,
) -> Vec<Annotatable> {
+ check_builtin_macro_attribute(cx, meta_item, sym::test);
expand_test_or_bench(cx, attr_sp, item, false)
}
pub fn expand_bench(
cx: &mut ExtCtxt<'_>,
attr_sp: Span,
- _meta_item: &ast::MetaItem,
+ meta_item: &ast::MetaItem,
item: Annotatable,
) -> Vec<Annotatable> {
+ check_builtin_macro_attribute(cx, meta_item, sym::bench);
expand_test_or_bench(cx, attr_sp, item, true)
}
// We mark item with an inert attribute "rustc_test_marker" which the test generation
// logic will pick up on.
+use syntax::ast;
+use syntax::attr::check_builtin_macro_attribute;
use syntax::ext::base::*;
use syntax::ext::build::AstBuilder;
use syntax::ext::hygiene::SyntaxContext;
-use syntax::ast;
use syntax::source_map::respan;
use syntax::symbol::sym;
use syntax_pos::Span;
pub fn expand(
ecx: &mut ExtCtxt<'_>,
attr_sp: Span,
- _meta_item: &ast::MetaItem,
+ meta_item: &ast::MetaItem,
anno_item: Annotatable
) -> Vec<Annotatable> {
+ check_builtin_macro_attribute(ecx, meta_item, sym::test_case);
+
if !ecx.ecfg.should_test { return vec![]; }
let sp = attr_sp.with_ctxt(SyntaxContext::empty().apply_mark(ecx.current_expansion.id));
--> $DIR/allocator-args.rs:10:1
|
LL | #[global_allocator(malloc)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: ``#[global_allocator]``
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[global_allocator]`
error: aborting due to previous error
+error: malformed `bench` attribute input
+ --> $DIR/issue-43106-gating-of-bench.rs:15:1
+ |
+LL | #![bench = "4100"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[bench]`
+
error[E0601]: `main` function not found in crate `issue_43106_gating_of_bench`
|
= note: consider adding a `main` function to `$DIR/issue-43106-gating-of-bench.rs`
-error: aborting due to previous error
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0601`.
+error: malformed `test` attribute input
+ --> $DIR/issue-43106-gating-of-test.rs:10:1
+ |
+LL | #![test = "4200"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[test]`
+
error[E0601]: `main` function not found in crate `issue_43106_gating_of_test`
|
= note: consider adding a `main` function to `$DIR/issue-43106-gating-of-test.rs`
-error: aborting due to previous error
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0601`.