Liberalize attributes.
This commit is contained in:
parent
68c1cc68b4
commit
839c2860cc
17 changed files with 257 additions and 172 deletions
|
@ -1165,6 +1165,7 @@ pub struct Resolver<'a> {
|
||||||
|
|
||||||
privacy_errors: Vec<PrivacyError<'a>>,
|
privacy_errors: Vec<PrivacyError<'a>>,
|
||||||
ambiguity_errors: Vec<AmbiguityError<'a>>,
|
ambiguity_errors: Vec<AmbiguityError<'a>>,
|
||||||
|
gated_errors: FxHashSet<Span>,
|
||||||
disallowed_shadowing: Vec<&'a LegacyBinding<'a>>,
|
disallowed_shadowing: Vec<&'a LegacyBinding<'a>>,
|
||||||
|
|
||||||
arenas: &'a ResolverArenas<'a>,
|
arenas: &'a ResolverArenas<'a>,
|
||||||
|
@ -1355,6 +1356,7 @@ impl<'a> Resolver<'a> {
|
||||||
|
|
||||||
privacy_errors: Vec::new(),
|
privacy_errors: Vec::new(),
|
||||||
ambiguity_errors: Vec::new(),
|
ambiguity_errors: Vec::new(),
|
||||||
|
gated_errors: FxHashSet(),
|
||||||
disallowed_shadowing: Vec::new(),
|
disallowed_shadowing: Vec::new(),
|
||||||
|
|
||||||
arenas: arenas,
|
arenas: arenas,
|
||||||
|
|
|
@ -28,9 +28,11 @@ use syntax::ext::placeholders::placeholder;
|
||||||
use syntax::ext::tt::macro_rules;
|
use syntax::ext::tt::macro_rules;
|
||||||
use syntax::feature_gate::{self, emit_feature_err, GateIssue};
|
use syntax::feature_gate::{self, emit_feature_err, GateIssue};
|
||||||
use syntax::fold::{self, Folder};
|
use syntax::fold::{self, Folder};
|
||||||
|
use syntax::parse::parser::PathStyle;
|
||||||
|
use syntax::parse::token::{self, Token};
|
||||||
use syntax::ptr::P;
|
use syntax::ptr::P;
|
||||||
use syntax::symbol::{Symbol, keywords};
|
use syntax::symbol::{Symbol, keywords};
|
||||||
use syntax::tokenstream::TokenStream;
|
use syntax::tokenstream::{TokenStream, TokenTree, Delimited};
|
||||||
use syntax::util::lev_distance::find_best_match_for_name;
|
use syntax::util::lev_distance::find_best_match_for_name;
|
||||||
use syntax_pos::{Span, DUMMY_SP};
|
use syntax_pos::{Span, DUMMY_SP};
|
||||||
|
|
||||||
|
@ -200,16 +202,22 @@ impl<'a> base::Resolver for Resolver<'a> {
|
||||||
let name = unwrap_or!(attrs[i].name(), continue);
|
let name = unwrap_or!(attrs[i].name(), continue);
|
||||||
|
|
||||||
if name == "derive" {
|
if name == "derive" {
|
||||||
let mut traits = match attrs[i].meta_item_list() {
|
let result = attrs[i].parse_list(&self.session.parse_sess,
|
||||||
Some(traits) => traits,
|
|parser| parser.parse_path(PathStyle::Mod));
|
||||||
_ => continue,
|
let mut traits = match result {
|
||||||
|
Ok(traits) => traits,
|
||||||
|
Err(mut e) => {
|
||||||
|
e.cancel();
|
||||||
|
continue
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for j in 0..traits.len() {
|
for j in 0..traits.len() {
|
||||||
let legacy_name = Symbol::intern(&match traits[j].word() {
|
if traits[j].segments.len() > 1 {
|
||||||
Some(..) => format!("derive_{}", traits[j].name().unwrap()),
|
continue
|
||||||
None => continue,
|
}
|
||||||
});
|
let trait_name = traits[j].segments[0].identifier.name;
|
||||||
|
let legacy_name = Symbol::intern(&format!("derive_{}", trait_name));
|
||||||
if !self.builtin_macros.contains_key(&legacy_name) {
|
if !self.builtin_macros.contains_key(&legacy_name) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -218,7 +226,23 @@ impl<'a> base::Resolver for Resolver<'a> {
|
||||||
if traits.is_empty() {
|
if traits.is_empty() {
|
||||||
attrs.remove(i);
|
attrs.remove(i);
|
||||||
} else {
|
} else {
|
||||||
attrs[i].tokens = ast::MetaItemKind::List(traits).tokens(attrs[i].span);
|
let mut tokens = Vec::new();
|
||||||
|
for (i, path) in traits.iter().enumerate() {
|
||||||
|
if i > 0 {
|
||||||
|
tokens.push(TokenTree::Token(attrs[i].span, Token::Comma).into());
|
||||||
|
}
|
||||||
|
for (j, segment) in path.segments.iter().enumerate() {
|
||||||
|
if j > 0 {
|
||||||
|
tokens.push(TokenTree::Token(path.span, Token::ModSep).into());
|
||||||
|
}
|
||||||
|
let tok = Token::Ident(segment.identifier);
|
||||||
|
tokens.push(TokenTree::Token(path.span, tok).into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attrs[i].tokens = TokenTree::Delimited(attrs[i].span, Delimited {
|
||||||
|
delim: token::Paren,
|
||||||
|
tts: TokenStream::concat(tokens).into(),
|
||||||
|
}).into();
|
||||||
}
|
}
|
||||||
return Some(ast::Attribute {
|
return Some(ast::Attribute {
|
||||||
path: ast::Path::from_ident(span, Ident::with_empty_ctxt(legacy_name)),
|
path: ast::Path::from_ident(span, Ident::with_empty_ctxt(legacy_name)),
|
||||||
|
@ -262,9 +286,8 @@ impl<'a> Resolver<'a> {
|
||||||
InvocationKind::Bang { ref mac, .. } => {
|
InvocationKind::Bang { ref mac, .. } => {
|
||||||
return self.resolve_macro_to_def(scope, &mac.node.path, MacroKind::Bang, force);
|
return self.resolve_macro_to_def(scope, &mac.node.path, MacroKind::Bang, force);
|
||||||
}
|
}
|
||||||
InvocationKind::Derive { name, span, .. } => {
|
InvocationKind::Derive { ref path, .. } => {
|
||||||
let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name));
|
return self.resolve_macro_to_def(scope, path, MacroKind::Derive, force);
|
||||||
return self.resolve_macro_to_def(scope, &path, MacroKind::Derive, force);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -282,9 +305,8 @@ impl<'a> Resolver<'a> {
|
||||||
1 => path.segments[0].identifier.name,
|
1 => path.segments[0].identifier.name,
|
||||||
_ => return Err(determinacy),
|
_ => return Err(determinacy),
|
||||||
};
|
};
|
||||||
for &(name, span) in traits {
|
for path in traits {
|
||||||
let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name));
|
match self.resolve_macro(scope, path, MacroKind::Derive, force) {
|
||||||
match self.resolve_macro(scope, &path, MacroKind::Derive, force) {
|
|
||||||
Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs) = *ext {
|
Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs) = *ext {
|
||||||
if inert_attrs.contains(&attr_name) {
|
if inert_attrs.contains(&attr_name) {
|
||||||
// FIXME(jseyfried) Avoid `mem::replace` here.
|
// FIXME(jseyfried) Avoid `mem::replace` here.
|
||||||
|
@ -327,7 +349,7 @@ impl<'a> Resolver<'a> {
|
||||||
self.current_module = invocation.module.get();
|
self.current_module = invocation.module.get();
|
||||||
|
|
||||||
if path.len() > 1 {
|
if path.len() > 1 {
|
||||||
if !self.use_extern_macros {
|
if !self.use_extern_macros && self.gated_errors.insert(span) {
|
||||||
let msg = "non-ident macro paths are experimental";
|
let msg = "non-ident macro paths are experimental";
|
||||||
let feature = "use_extern_macros";
|
let feature = "use_extern_macros";
|
||||||
emit_feature_err(&self.session.parse_sess, feature, span, GateIssue::Language, msg);
|
emit_feature_err(&self.session.parse_sess, feature, span, GateIssue::Language, msg);
|
||||||
|
|
|
@ -17,7 +17,7 @@ pub use self::IntType::*;
|
||||||
use ast;
|
use ast;
|
||||||
use ast::{AttrId, Attribute, Name, Ident};
|
use ast::{AttrId, Attribute, Name, Ident};
|
||||||
use ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind};
|
use ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind};
|
||||||
use ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind};
|
use ast::{Lit, LitKind, Expr, ExprKind, Item, Local, Stmt, StmtKind};
|
||||||
use codemap::{Spanned, spanned, dummy_spanned, mk_sp};
|
use codemap::{Spanned, spanned, dummy_spanned, mk_sp};
|
||||||
use syntax_pos::{Span, BytePos, DUMMY_SP};
|
use syntax_pos::{Span, BytePos, DUMMY_SP};
|
||||||
use errors::Handler;
|
use errors::Handler;
|
||||||
|
@ -299,6 +299,37 @@ impl Attribute {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, T>
|
||||||
|
where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
|
||||||
|
{
|
||||||
|
let mut parser = Parser::new(sess, self.tokens.clone(), None, false);
|
||||||
|
let result = f(&mut parser)?;
|
||||||
|
if parser.token != token::Eof {
|
||||||
|
parser.unexpected()?;
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_list<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, Vec<T>>
|
||||||
|
where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
|
||||||
|
{
|
||||||
|
if self.tokens.is_empty() {
|
||||||
|
return Ok(Vec::new());
|
||||||
|
}
|
||||||
|
self.parse(sess, |parser| {
|
||||||
|
parser.expect(&token::OpenDelim(token::Paren))?;
|
||||||
|
let mut list = Vec::new();
|
||||||
|
while !parser.eat(&token::CloseDelim(token::Paren)) {
|
||||||
|
list.push(f(parser)?);
|
||||||
|
if !parser.eat(&token::Comma) {
|
||||||
|
parser.expect(&token::CloseDelim(token::Paren))?;
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(list)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse_meta<'a>(&self, sess: &'a ParseSess) -> PResult<'a, MetaItem> {
|
pub fn parse_meta<'a>(&self, sess: &'a ParseSess) -> PResult<'a, MetaItem> {
|
||||||
if self.path.segments.len() > 1 {
|
if self.path.segments.len() > 1 {
|
||||||
sess.span_diagnostic.span_err(self.path.span, "expected ident, found path");
|
sess.span_diagnostic.span_err(self.path.span, "expected ident, found path");
|
||||||
|
@ -306,7 +337,7 @@ impl Attribute {
|
||||||
|
|
||||||
Ok(MetaItem {
|
Ok(MetaItem {
|
||||||
name: self.path.segments.last().unwrap().identifier.name,
|
name: self.path.segments.last().unwrap().identifier.name,
|
||||||
node: Parser::new(sess, self.tokens.clone(), None, false).parse_meta_item_kind()?,
|
node: self.parse(sess, |parser| parser.parse_meta_item_kind())?,
|
||||||
span: self.span,
|
span: self.span,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -985,6 +1016,10 @@ impl MetaItem {
|
||||||
{
|
{
|
||||||
let (mut span, name) = match tokens.next() {
|
let (mut span, name) = match tokens.next() {
|
||||||
Some(TokenTree::Token(span, Token::Ident(ident))) => (span, ident.name),
|
Some(TokenTree::Token(span, Token::Ident(ident))) => (span, ident.name),
|
||||||
|
Some(TokenTree::Token(_, Token::Interpolated(ref nt))) => return match **nt {
|
||||||
|
token::Nonterminal::NtMeta(ref meta) => Some(meta.clone()),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
let node = match MetaItemKind::from_tokens(tokens) {
|
let node = match MetaItemKind::from_tokens(tokens) {
|
||||||
|
@ -1151,6 +1186,13 @@ impl LitKind {
|
||||||
match token {
|
match token {
|
||||||
Token::Ident(ident) if ident.name == "true" => Some(LitKind::Bool(true)),
|
Token::Ident(ident) if ident.name == "true" => Some(LitKind::Bool(true)),
|
||||||
Token::Ident(ident) if ident.name == "false" => Some(LitKind::Bool(false)),
|
Token::Ident(ident) if ident.name == "false" => Some(LitKind::Bool(false)),
|
||||||
|
Token::Interpolated(ref nt) => match **nt {
|
||||||
|
token::NtExpr(ref v) => match v.node {
|
||||||
|
ExprKind::Lit(ref lit) => Some(lit.node.clone()),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
Token::Literal(lit, suf) => {
|
Token::Literal(lit, suf) => {
|
||||||
let (suffix_illegal, result) = parse::lit_token(lit, suf, None);
|
let (suffix_illegal, result) = parse::lit_token(lit, suf, None);
|
||||||
if suffix_illegal && suf.is_some() {
|
if suffix_illegal && suf.is_some() {
|
||||||
|
|
|
@ -13,9 +13,10 @@ use feature_gate::{feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features
|
||||||
use {fold, attr};
|
use {fold, attr};
|
||||||
use ast;
|
use ast;
|
||||||
use codemap::Spanned;
|
use codemap::Spanned;
|
||||||
use parse::ParseSess;
|
use parse::{token, ParseSess};
|
||||||
use ptr::P;
|
use syntax_pos::Span;
|
||||||
|
|
||||||
|
use ptr::P;
|
||||||
use util::small_vector::SmallVector;
|
use util::small_vector::SmallVector;
|
||||||
|
|
||||||
/// A folder that strips out items that do not belong in the current configuration.
|
/// A folder that strips out items that do not belong in the current configuration.
|
||||||
|
@ -84,44 +85,33 @@ impl<'a> StripUnconfigured<'a> {
|
||||||
return Some(attr);
|
return Some(attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
let attr_list = match attr.meta_item_list() {
|
let (cfg, path, tokens, span) = match attr.parse(self.sess, |parser| {
|
||||||
Some(attr_list) => attr_list,
|
parser.expect(&token::OpenDelim(token::Paren))?;
|
||||||
None => {
|
let cfg = parser.parse_meta_item()?;
|
||||||
let msg = "expected `#[cfg_attr(<cfg pattern>, <attr>)]`";
|
parser.expect(&token::Comma)?;
|
||||||
self.sess.span_diagnostic.span_err(attr.span, msg);
|
let lo = parser.span.lo;
|
||||||
|
let (path, tokens) = parser.parse_path_and_tokens()?;
|
||||||
|
parser.expect(&token::CloseDelim(token::Paren))?;
|
||||||
|
Ok((cfg, path, tokens, Span { lo: lo, ..parser.prev_span }))
|
||||||
|
}) {
|
||||||
|
Ok(result) => result,
|
||||||
|
Err(mut e) => {
|
||||||
|
e.emit();
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let (cfg, mi) = match (attr_list.len(), attr_list.get(0), attr_list.get(1)) {
|
if attr::cfg_matches(&cfg, self.sess, self.features) {
|
||||||
(2, Some(cfg), Some(mi)) => (cfg, mi),
|
self.process_cfg_attr(ast::Attribute {
|
||||||
_ => {
|
id: attr::mk_attr_id(),
|
||||||
let msg = "expected `#[cfg_attr(<cfg pattern>, <attr>)]`";
|
style: attr.style,
|
||||||
self.sess.span_diagnostic.span_err(attr.span, msg);
|
path: path,
|
||||||
return None;
|
tokens: tokens,
|
||||||
}
|
is_sugared_doc: false,
|
||||||
};
|
span: span,
|
||||||
|
})
|
||||||
use attr::cfg_matches;
|
} else {
|
||||||
match (cfg.meta_item(), mi.meta_item()) {
|
None
|
||||||
(Some(cfg), Some(mi)) =>
|
|
||||||
if cfg_matches(&cfg, self.sess, self.features) {
|
|
||||||
self.process_cfg_attr(ast::Attribute {
|
|
||||||
id: attr::mk_attr_id(),
|
|
||||||
style: attr.style,
|
|
||||||
path: ast::Path::from_ident(mi.span, ast::Ident::with_empty_ctxt(mi.name)),
|
|
||||||
tokens: mi.node.tokens(mi.span),
|
|
||||||
is_sugared_doc: false,
|
|
||||||
span: mi.span,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
let msg = "unexpected literal(s) in `#[cfg_attr(<cfg pattern>, <attr>)]`";
|
|
||||||
self.sess.span_diagnostic.span_err(attr.span, msg);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,10 +123,12 @@ impl<'a> StripUnconfigured<'a> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mis = attr.meta_item_list();
|
let mis = if !is_cfg(&attr) {
|
||||||
let mis = match mis {
|
return true;
|
||||||
Some(ref mis) if is_cfg(&attr) => mis,
|
} else if let Some(mis) = attr.meta_item_list() {
|
||||||
_ => return true
|
mis
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
if mis.len() != 1 {
|
if mis.len() != 1 {
|
||||||
|
|
|
@ -12,36 +12,31 @@ use attr::HasAttrs;
|
||||||
use {ast, codemap};
|
use {ast, codemap};
|
||||||
use ext::base::ExtCtxt;
|
use ext::base::ExtCtxt;
|
||||||
use ext::build::AstBuilder;
|
use ext::build::AstBuilder;
|
||||||
|
use parse::parser::PathStyle;
|
||||||
use symbol::Symbol;
|
use symbol::Symbol;
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
|
|
||||||
pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>) -> Vec<(Symbol, Span)> {
|
pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>) -> Vec<ast::Path> {
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
attrs.retain(|attr| {
|
attrs.retain(|attr| {
|
||||||
if attr.path != "derive" {
|
if attr.path != "derive" {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if attr.value_str().is_some() {
|
match attr.parse_list(cx.parse_sess, |parser| parser.parse_path(PathStyle::Mod)) {
|
||||||
cx.span_err(attr.span, "unexpected value in `derive`");
|
Ok(ref traits) if traits.is_empty() => {
|
||||||
return false;
|
cx.span_warn(attr.span, "empty trait list in `derive`");
|
||||||
}
|
false
|
||||||
|
}
|
||||||
let traits = attr.meta_item_list().unwrap_or_else(Vec::new);
|
Ok(traits) => {
|
||||||
if traits.is_empty() {
|
result.extend(traits);
|
||||||
cx.span_warn(attr.span, "empty trait list in `derive`");
|
true
|
||||||
return false;
|
}
|
||||||
}
|
Err(mut e) => {
|
||||||
|
e.emit();
|
||||||
for titem in traits {
|
false
|
||||||
if titem.word().is_none() {
|
|
||||||
cx.span_err(titem.span, "malformed `derive` entry");
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
result.push((titem.name().unwrap(), titem.span));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
|
||||||
});
|
});
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
@ -60,21 +55,21 @@ fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_derived_markers<T: HasAttrs>(cx: &mut ExtCtxt, traits: &[(Symbol, Span)], item: T) -> T {
|
pub fn add_derived_markers<T: HasAttrs>(cx: &mut ExtCtxt, traits: &[ast::Path], item: T) -> T {
|
||||||
let span = match traits.get(0) {
|
let span = match traits.get(0) {
|
||||||
Some(&(_, span)) => span,
|
Some(path) => path.span,
|
||||||
None => return item,
|
None => return item,
|
||||||
};
|
};
|
||||||
|
|
||||||
item.map_attrs(|mut attrs| {
|
item.map_attrs(|mut attrs| {
|
||||||
if traits.iter().any(|&(name, _)| name == "PartialEq") &&
|
if traits.iter().any(|path| *path == "PartialEq") &&
|
||||||
traits.iter().any(|&(name, _)| name == "Eq") {
|
traits.iter().any(|path| *path == "Eq") {
|
||||||
let span = allow_unstable(cx, span, "derive(PartialEq, Eq)");
|
let span = allow_unstable(cx, span, "derive(PartialEq, Eq)");
|
||||||
let meta = cx.meta_word(span, Symbol::intern("structural_match"));
|
let meta = cx.meta_word(span, Symbol::intern("structural_match"));
|
||||||
attrs.push(cx.attribute(span, meta));
|
attrs.push(cx.attribute(span, meta));
|
||||||
}
|
}
|
||||||
if traits.iter().any(|&(name, _)| name == "Copy") &&
|
if traits.iter().any(|path| *path == "Copy") &&
|
||||||
traits.iter().any(|&(name, _)| name == "Clone") {
|
traits.iter().any(|path| *path == "Clone") {
|
||||||
let span = allow_unstable(cx, span, "derive(Copy, Clone)");
|
let span = allow_unstable(cx, span, "derive(Copy, Clone)");
|
||||||
let meta = cx.meta_word(span, Symbol::intern("rustc_copy_clone_marker"));
|
let meta = cx.meta_word(span, Symbol::intern("rustc_copy_clone_marker"));
|
||||||
attrs.push(cx.attribute(span, meta));
|
attrs.push(cx.attribute(span, meta));
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use ast::{self, Block, Ident, PatKind};
|
use ast::{self, Block, Ident, PatKind, Path};
|
||||||
use ast::{Name, MacStmtStyle, StmtKind, ItemKind};
|
use ast::{MacStmtStyle, StmtKind, ItemKind};
|
||||||
use attr::{self, HasAttrs};
|
use attr::{self, HasAttrs};
|
||||||
use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
|
use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
|
||||||
use config::{is_test_or_bench, StripUnconfigured};
|
use config::{is_test_or_bench, StripUnconfigured};
|
||||||
|
@ -27,7 +27,7 @@ use ptr::P;
|
||||||
use std_inject;
|
use std_inject;
|
||||||
use symbol::Symbol;
|
use symbol::Symbol;
|
||||||
use symbol::keywords;
|
use symbol::keywords;
|
||||||
use syntax_pos::{self, Span, ExpnId};
|
use syntax_pos::{Span, ExpnId, DUMMY_SP};
|
||||||
use tokenstream::TokenStream;
|
use tokenstream::TokenStream;
|
||||||
use util::small_vector::SmallVector;
|
use util::small_vector::SmallVector;
|
||||||
use visit::Visitor;
|
use visit::Visitor;
|
||||||
|
@ -165,12 +165,11 @@ pub enum InvocationKind {
|
||||||
},
|
},
|
||||||
Attr {
|
Attr {
|
||||||
attr: Option<ast::Attribute>,
|
attr: Option<ast::Attribute>,
|
||||||
traits: Vec<(Symbol, Span)>,
|
traits: Vec<Path>,
|
||||||
item: Annotatable,
|
item: Annotatable,
|
||||||
},
|
},
|
||||||
Derive {
|
Derive {
|
||||||
name: Symbol,
|
path: Path,
|
||||||
span: Span,
|
|
||||||
item: Annotatable,
|
item: Annotatable,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -180,8 +179,8 @@ impl Invocation {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
InvocationKind::Bang { span, .. } => span,
|
InvocationKind::Bang { span, .. } => span,
|
||||||
InvocationKind::Attr { attr: Some(ref attr), .. } => attr.span,
|
InvocationKind::Attr { attr: Some(ref attr), .. } => attr.span,
|
||||||
InvocationKind::Attr { attr: None, .. } => syntax_pos::DUMMY_SP,
|
InvocationKind::Attr { attr: None, .. } => DUMMY_SP,
|
||||||
InvocationKind::Derive { span, .. } => span,
|
InvocationKind::Derive { ref path, .. } => path.span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -277,12 +276,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
add_derived_markers(&mut self.cx, &traits, item.clone());
|
add_derived_markers(&mut self.cx, &traits, item.clone());
|
||||||
let derives = derives.entry(invoc.expansion_data.mark).or_insert_with(Vec::new);
|
let derives = derives.entry(invoc.expansion_data.mark).or_insert_with(Vec::new);
|
||||||
|
|
||||||
for &(name, span) in &traits {
|
for path in &traits {
|
||||||
let mark = Mark::fresh();
|
let mark = Mark::fresh();
|
||||||
derives.push(mark);
|
derives.push(mark);
|
||||||
let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name));
|
|
||||||
let item = match self.cx.resolver.resolve_macro(
|
let item = match self.cx.resolver.resolve_macro(
|
||||||
Mark::root(), &path, MacroKind::Derive, false) {
|
Mark::root(), path, MacroKind::Derive, false) {
|
||||||
Ok(ext) => match *ext {
|
Ok(ext) => match *ext {
|
||||||
SyntaxExtension::BuiltinDerive(..) => item_with_markers.clone(),
|
SyntaxExtension::BuiltinDerive(..) => item_with_markers.clone(),
|
||||||
_ => item.clone(),
|
_ => item.clone(),
|
||||||
|
@ -290,7 +288,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
_ => item.clone(),
|
_ => item.clone(),
|
||||||
};
|
};
|
||||||
invocations.push(Invocation {
|
invocations.push(Invocation {
|
||||||
kind: InvocationKind::Derive { name: name, span: span, item: item },
|
kind: InvocationKind::Derive { path: path.clone(), item: item },
|
||||||
expansion_kind: invoc.expansion_kind,
|
expansion_kind: invoc.expansion_kind,
|
||||||
expansion_data: ExpansionData {
|
expansion_data: ExpansionData {
|
||||||
mark: mark,
|
mark: mark,
|
||||||
|
@ -380,11 +378,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
};
|
};
|
||||||
|
|
||||||
attr::mark_used(&attr);
|
attr::mark_used(&attr);
|
||||||
let name = attr.path.segments[0].identifier.name;
|
|
||||||
self.cx.bt_push(ExpnInfo {
|
self.cx.bt_push(ExpnInfo {
|
||||||
call_site: attr.span,
|
call_site: attr.span,
|
||||||
callee: NameAndSpan {
|
callee: NameAndSpan {
|
||||||
format: MacroAttribute(name),
|
format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))),
|
||||||
span: Some(attr.span),
|
span: Some(attr.span),
|
||||||
allow_internal_unstable: false,
|
allow_internal_unstable: false,
|
||||||
}
|
}
|
||||||
|
@ -419,14 +416,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let tok_result = mac.expand(self.cx, attr.span, attr.tokens.clone(), item_toks);
|
let tok_result = mac.expand(self.cx, attr.span, attr.tokens.clone(), item_toks);
|
||||||
self.parse_expansion(tok_result, kind, name, span)
|
self.parse_expansion(tok_result, kind, &attr.path, span)
|
||||||
}
|
}
|
||||||
SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => {
|
SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => {
|
||||||
self.cx.span_err(attr.span, &format!("`{}` is a derive mode", name));
|
self.cx.span_err(attr.span, &format!("`{}` is a derive mode", attr.path));
|
||||||
kind.dummy(attr.span)
|
kind.dummy(attr.span)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let msg = &format!("macro `{}` may not be used in attributes", name);
|
let msg = &format!("macro `{}` may not be used in attributes", attr.path);
|
||||||
self.cx.span_err(attr.span, &msg);
|
self.cx.span_err(attr.span, &msg);
|
||||||
kind.dummy(attr.span)
|
kind.dummy(attr.span)
|
||||||
}
|
}
|
||||||
|
@ -442,7 +439,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
};
|
};
|
||||||
let path = &mac.node.path;
|
let path = &mac.node.path;
|
||||||
|
|
||||||
let extname = path.segments.last().unwrap().identifier.name;
|
|
||||||
let ident = ident.unwrap_or(keywords::Invalid.ident());
|
let ident = ident.unwrap_or(keywords::Invalid.ident());
|
||||||
let marked_tts =
|
let marked_tts =
|
||||||
noop_fold_tts(mac.node.stream(), &mut Marker { mark: mark, expn_id: None });
|
noop_fold_tts(mac.node.stream(), &mut Marker { mark: mark, expn_id: None });
|
||||||
|
@ -450,7 +446,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
|
NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
|
||||||
if ident.name != keywords::Invalid.name() {
|
if ident.name != keywords::Invalid.name() {
|
||||||
let msg =
|
let msg =
|
||||||
format!("macro {}! expects no ident argument, given '{}'", extname, ident);
|
format!("macro {}! expects no ident argument, given '{}'", path, ident);
|
||||||
self.cx.span_err(path.span, &msg);
|
self.cx.span_err(path.span, &msg);
|
||||||
return kind.dummy(span);
|
return kind.dummy(span);
|
||||||
}
|
}
|
||||||
|
@ -458,7 +454,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
self.cx.bt_push(ExpnInfo {
|
self.cx.bt_push(ExpnInfo {
|
||||||
call_site: span,
|
call_site: span,
|
||||||
callee: NameAndSpan {
|
callee: NameAndSpan {
|
||||||
format: MacroBang(extname),
|
format: MacroBang(Symbol::intern(&format!("{}", path))),
|
||||||
span: exp_span,
|
span: exp_span,
|
||||||
allow_internal_unstable: allow_internal_unstable,
|
allow_internal_unstable: allow_internal_unstable,
|
||||||
},
|
},
|
||||||
|
@ -470,14 +466,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
IdentTT(ref expander, tt_span, allow_internal_unstable) => {
|
IdentTT(ref expander, tt_span, allow_internal_unstable) => {
|
||||||
if ident.name == keywords::Invalid.name() {
|
if ident.name == keywords::Invalid.name() {
|
||||||
self.cx.span_err(path.span,
|
self.cx.span_err(path.span,
|
||||||
&format!("macro {}! expects an ident argument", extname));
|
&format!("macro {}! expects an ident argument", path));
|
||||||
return kind.dummy(span);
|
return kind.dummy(span);
|
||||||
};
|
};
|
||||||
|
|
||||||
self.cx.bt_push(ExpnInfo {
|
self.cx.bt_push(ExpnInfo {
|
||||||
call_site: span,
|
call_site: span,
|
||||||
callee: NameAndSpan {
|
callee: NameAndSpan {
|
||||||
format: MacroBang(extname),
|
format: MacroBang(Symbol::intern(&format!("{}", path))),
|
||||||
span: tt_span,
|
span: tt_span,
|
||||||
allow_internal_unstable: allow_internal_unstable,
|
allow_internal_unstable: allow_internal_unstable,
|
||||||
}
|
}
|
||||||
|
@ -489,19 +485,19 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
|
|
||||||
MultiDecorator(..) | MultiModifier(..) | SyntaxExtension::AttrProcMacro(..) => {
|
MultiDecorator(..) | MultiModifier(..) | SyntaxExtension::AttrProcMacro(..) => {
|
||||||
self.cx.span_err(path.span,
|
self.cx.span_err(path.span,
|
||||||
&format!("`{}` can only be used in attributes", extname));
|
&format!("`{}` can only be used in attributes", path));
|
||||||
return kind.dummy(span);
|
return kind.dummy(span);
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => {
|
SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => {
|
||||||
self.cx.span_err(path.span, &format!("`{}` is a derive mode", extname));
|
self.cx.span_err(path.span, &format!("`{}` is a derive mode", path));
|
||||||
return kind.dummy(span);
|
return kind.dummy(span);
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxExtension::ProcMacro(ref expandfun) => {
|
SyntaxExtension::ProcMacro(ref expandfun) => {
|
||||||
if ident.name != keywords::Invalid.name() {
|
if ident.name != keywords::Invalid.name() {
|
||||||
let msg =
|
let msg =
|
||||||
format!("macro {}! expects no ident argument, given '{}'", extname, ident);
|
format!("macro {}! expects no ident argument, given '{}'", path, ident);
|
||||||
self.cx.span_err(path.span, &msg);
|
self.cx.span_err(path.span, &msg);
|
||||||
return kind.dummy(span);
|
return kind.dummy(span);
|
||||||
}
|
}
|
||||||
|
@ -509,7 +505,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
self.cx.bt_push(ExpnInfo {
|
self.cx.bt_push(ExpnInfo {
|
||||||
call_site: span,
|
call_site: span,
|
||||||
callee: NameAndSpan {
|
callee: NameAndSpan {
|
||||||
format: MacroBang(extname),
|
format: MacroBang(Symbol::intern(&format!("{}", path))),
|
||||||
// FIXME procedural macros do not have proper span info
|
// FIXME procedural macros do not have proper span info
|
||||||
// yet, when they do, we should use it here.
|
// yet, when they do, we should use it here.
|
||||||
span: None,
|
span: None,
|
||||||
|
@ -519,7 +515,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
});
|
});
|
||||||
|
|
||||||
let tok_result = expandfun.expand(self.cx, span, marked_tts);
|
let tok_result = expandfun.expand(self.cx, span, marked_tts);
|
||||||
Some(self.parse_expansion(tok_result, kind, extname, span))
|
Some(self.parse_expansion(tok_result, kind, path, span))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -541,19 +537,24 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
/// Expand a derive invocation. Returns the result of expansion.
|
/// Expand a derive invocation. Returns the result of expansion.
|
||||||
fn expand_derive_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Expansion {
|
fn expand_derive_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Expansion {
|
||||||
let Invocation { expansion_kind: kind, .. } = invoc;
|
let Invocation { expansion_kind: kind, .. } = invoc;
|
||||||
let (name, span, item) = match invoc.kind {
|
let (path, item) = match invoc.kind {
|
||||||
InvocationKind::Derive { name, span, item } => (name, span, item),
|
InvocationKind::Derive { path, item } => (path, item),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mitem = ast::MetaItem { name: name, span: span, node: ast::MetaItemKind::Word };
|
let pretty_name = Symbol::intern(&format!("derive({})", path));
|
||||||
let pretty_name = Symbol::intern(&format!("derive({})", name));
|
let span = path.span;
|
||||||
|
let attr = ast::Attribute {
|
||||||
|
path: path, tokens: TokenStream::empty(), span: span,
|
||||||
|
// irrelevant:
|
||||||
|
id: ast::AttrId(0), style: ast::AttrStyle::Outer, is_sugared_doc: false,
|
||||||
|
};
|
||||||
|
|
||||||
self.cx.bt_push(ExpnInfo {
|
self.cx.bt_push(ExpnInfo {
|
||||||
call_site: span,
|
call_site: span,
|
||||||
callee: NameAndSpan {
|
callee: NameAndSpan {
|
||||||
format: MacroAttribute(pretty_name),
|
format: MacroAttribute(pretty_name),
|
||||||
span: Some(span),
|
span: None,
|
||||||
allow_internal_unstable: false,
|
allow_internal_unstable: false,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -571,7 +572,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
}),
|
}),
|
||||||
..span
|
..span
|
||||||
};
|
};
|
||||||
return kind.expect_from_annotatables(ext.expand(self.cx, span, &mitem, item));
|
let dummy = ast::MetaItem { // FIXME(jseyfried) avoid this
|
||||||
|
name: keywords::Invalid.name(),
|
||||||
|
span: DUMMY_SP,
|
||||||
|
node: ast::MetaItemKind::Word,
|
||||||
|
};
|
||||||
|
return kind.expect_from_annotatables(ext.expand(self.cx, span, &dummy, item));
|
||||||
}
|
}
|
||||||
SyntaxExtension::BuiltinDerive(func) => {
|
SyntaxExtension::BuiltinDerive(func) => {
|
||||||
let span = Span {
|
let span = Span {
|
||||||
|
@ -586,20 +592,18 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
..span
|
..span
|
||||||
};
|
};
|
||||||
let mut items = Vec::new();
|
let mut items = Vec::new();
|
||||||
func(self.cx, span, &mitem, &item, &mut |a| {
|
func(self.cx, span, &attr.meta().unwrap(), &item, &mut |a| items.push(a));
|
||||||
items.push(a)
|
|
||||||
});
|
|
||||||
return kind.expect_from_annotatables(items);
|
return kind.expect_from_annotatables(items);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let msg = &format!("macro `{}` may not be used for derive attributes", name);
|
let msg = &format!("macro `{}` may not be used for derive attributes", attr.path);
|
||||||
self.cx.span_err(span, &msg);
|
self.cx.span_err(span, &msg);
|
||||||
kind.dummy(span)
|
kind.dummy(span)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_expansion(&mut self, toks: TokenStream, kind: ExpansionKind, name: Name, span: Span)
|
fn parse_expansion(&mut self, toks: TokenStream, kind: ExpansionKind, path: &Path, span: Span)
|
||||||
-> Expansion {
|
-> Expansion {
|
||||||
let mut parser = self.cx.new_parser_from_tts(&toks.into_trees().collect::<Vec<_>>());
|
let mut parser = self.cx.new_parser_from_tts(&toks.into_trees().collect::<Vec<_>>());
|
||||||
let expansion = match parser.parse_expansion(kind, false) {
|
let expansion = match parser.parse_expansion(kind, false) {
|
||||||
|
@ -609,7 +613,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
return kind.dummy(span);
|
return kind.dummy(span);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
parser.ensure_complete_parse(name, kind.name(), span);
|
parser.ensure_complete_parse(path, kind.name(), span);
|
||||||
// FIXME better span info
|
// FIXME better span info
|
||||||
expansion.fold_with(&mut ChangeSpan { span: span })
|
expansion.fold_with(&mut ChangeSpan { span: span })
|
||||||
}
|
}
|
||||||
|
@ -658,14 +662,14 @@ impl<'a> Parser<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ensure_complete_parse(&mut self, macro_name: ast::Name, kind_name: &str, span: Span) {
|
pub fn ensure_complete_parse(&mut self, macro_path: &Path, kind_name: &str, span: Span) {
|
||||||
if self.token != token::Eof {
|
if self.token != token::Eof {
|
||||||
let msg = format!("macro expansion ignores token `{}` and any following",
|
let msg = format!("macro expansion ignores token `{}` and any following",
|
||||||
self.this_token_to_string());
|
self.this_token_to_string());
|
||||||
let mut err = self.diagnostic().struct_span_err(self.span, &msg);
|
let mut err = self.diagnostic().struct_span_err(self.span, &msg);
|
||||||
let msg = format!("caused by the macro expansion here; the usage \
|
let msg = format!("caused by the macro expansion here; the usage \
|
||||||
of `{}!` is likely invalid in {} context",
|
of `{}!` is likely invalid in {} context",
|
||||||
macro_name, kind_name);
|
macro_path, kind_name);
|
||||||
err.span_note(span, &msg).emit();
|
err.span_note(span, &msg).emit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -708,20 +712,20 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
||||||
|
|
||||||
fn collect_attr(&mut self,
|
fn collect_attr(&mut self,
|
||||||
attr: Option<ast::Attribute>,
|
attr: Option<ast::Attribute>,
|
||||||
traits: Vec<(Symbol, Span)>,
|
traits: Vec<Path>,
|
||||||
item: Annotatable,
|
item: Annotatable,
|
||||||
kind: ExpansionKind)
|
kind: ExpansionKind)
|
||||||
-> Expansion {
|
-> Expansion {
|
||||||
if !traits.is_empty() &&
|
if !traits.is_empty() &&
|
||||||
(kind == ExpansionKind::TraitItems || kind == ExpansionKind::ImplItems) {
|
(kind == ExpansionKind::TraitItems || kind == ExpansionKind::ImplItems) {
|
||||||
self.cx.span_err(traits[0].1, "`derive` can be only be applied to items");
|
self.cx.span_err(traits[0].span, "`derive` can be only be applied to items");
|
||||||
return kind.expect_from_annotatables(::std::iter::once(item));
|
return kind.expect_from_annotatables(::std::iter::once(item));
|
||||||
}
|
}
|
||||||
self.collect(kind, InvocationKind::Attr { attr: attr, traits: traits, item: item })
|
self.collect(kind, InvocationKind::Attr { attr: attr, traits: traits, item: item })
|
||||||
}
|
}
|
||||||
|
|
||||||
// If `item` is an attr invocation, remove and return the macro attribute.
|
// If `item` is an attr invocation, remove and return the macro attribute.
|
||||||
fn classify_item<T>(&mut self, mut item: T) -> (Option<ast::Attribute>, Vec<(Symbol, Span)>, T)
|
fn classify_item<T>(&mut self, mut item: T) -> (Option<ast::Attribute>, Vec<Path>, T)
|
||||||
where T: HasAttrs,
|
where T: HasAttrs,
|
||||||
{
|
{
|
||||||
let (mut attr, mut traits) = (None, Vec::new());
|
let (mut attr, mut traits) = (None, Vec::new());
|
||||||
|
@ -900,7 +904,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
|
||||||
// Detect if this is an inline module (`mod m { ... }` as opposed to `mod m;`).
|
// Detect if this is an inline module (`mod m { ... }` as opposed to `mod m;`).
|
||||||
// In the non-inline case, `inner` is never the dummy span (c.f. `parse_item_mod`).
|
// In the non-inline case, `inner` is never the dummy span (c.f. `parse_item_mod`).
|
||||||
// Thus, if `inner` is the dummy span, we know the module is inline.
|
// Thus, if `inner` is the dummy span, we know the module is inline.
|
||||||
let inline_module = item.span.contains(inner) || inner == syntax_pos::DUMMY_SP;
|
let inline_module = item.span.contains(inner) || inner == DUMMY_SP;
|
||||||
|
|
||||||
if inline_module {
|
if inline_module {
|
||||||
if let Some(path) = attr::first_attr_value_str_by_name(&item.attrs, "path") {
|
if let Some(path) = attr::first_attr_value_str_by_name(&item.attrs, "path") {
|
||||||
|
|
|
@ -51,7 +51,8 @@ impl<'a> ParserAnyMacro<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure we don't have any tokens left to parse so we don't silently drop anything.
|
// Make sure we don't have any tokens left to parse so we don't silently drop anything.
|
||||||
parser.ensure_complete_parse(macro_ident.name, kind.name(), site_span);
|
let path = ast::Path::from_ident(site_span, macro_ident);
|
||||||
|
parser.ensure_complete_parse(&path, kind.name(), site_span);
|
||||||
expansion
|
expansion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1096,6 +1096,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||||
self.context.check_attribute(attr, false);
|
self.context.check_attribute(attr, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.context.features.proc_macro && attr::is_known(attr) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
let meta = panictry!(attr.parse_meta(&self.context.parse_sess));
|
let meta = panictry!(attr.parse_meta(&self.context.parse_sess));
|
||||||
if contains_novel_literal(&meta) {
|
if contains_novel_literal(&meta) {
|
||||||
gate_feature_post!(&self, attr_literals, attr.span,
|
gate_feature_post!(&self, attr_literals, attr.span,
|
||||||
|
|
|
@ -14,8 +14,9 @@ use syntax_pos::{mk_sp, Span};
|
||||||
use codemap::spanned;
|
use codemap::spanned;
|
||||||
use parse::common::SeqSep;
|
use parse::common::SeqSep;
|
||||||
use parse::PResult;
|
use parse::PResult;
|
||||||
use parse::token;
|
use parse::token::{self, Nonterminal};
|
||||||
use parse::parser::{Parser, TokenType};
|
use parse::parser::{Parser, TokenType, PathStyle};
|
||||||
|
use tokenstream::TokenStream;
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug)]
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
enum InnerAttributeParsePolicy<'a> {
|
enum InnerAttributeParsePolicy<'a> {
|
||||||
|
@ -91,7 +92,7 @@ impl<'a> Parser<'a> {
|
||||||
debug!("parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}",
|
debug!("parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}",
|
||||||
inner_parse_policy,
|
inner_parse_policy,
|
||||||
self.token);
|
self.token);
|
||||||
let (span, value, mut style) = match self.token {
|
let (span, path, tokens, mut style) = match self.token {
|
||||||
token::Pound => {
|
token::Pound => {
|
||||||
let lo = self.span.lo;
|
let lo = self.span.lo;
|
||||||
self.bump();
|
self.bump();
|
||||||
|
@ -119,11 +120,11 @@ impl<'a> Parser<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
self.expect(&token::OpenDelim(token::Bracket))?;
|
self.expect(&token::OpenDelim(token::Bracket))?;
|
||||||
let meta_item = self.parse_meta_item()?;
|
let (path, tokens) = self.parse_path_and_tokens()?;
|
||||||
self.expect(&token::CloseDelim(token::Bracket))?;
|
self.expect(&token::CloseDelim(token::Bracket))?;
|
||||||
let hi = self.prev_span.hi;
|
let hi = self.prev_span.hi;
|
||||||
|
|
||||||
(mk_sp(lo, hi), meta_item, style)
|
(mk_sp(lo, hi), path, tokens, style)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let token_str = self.this_token_to_string();
|
let token_str = self.this_token_to_string();
|
||||||
|
@ -143,13 +144,30 @@ impl<'a> Parser<'a> {
|
||||||
Ok(ast::Attribute {
|
Ok(ast::Attribute {
|
||||||
id: attr::mk_attr_id(),
|
id: attr::mk_attr_id(),
|
||||||
style: style,
|
style: style,
|
||||||
path: ast::Path::from_ident(value.span, ast::Ident::with_empty_ctxt(value.name)),
|
path: path,
|
||||||
tokens: value.node.tokens(value.span),
|
tokens: tokens,
|
||||||
is_sugared_doc: false,
|
is_sugared_doc: false,
|
||||||
span: span,
|
span: span,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse_path_and_tokens(&mut self) -> PResult<'a, (ast::Path, TokenStream)> {
|
||||||
|
let meta = match self.token {
|
||||||
|
token::Interpolated(ref nt) => match **nt {
|
||||||
|
Nonterminal::NtMeta(ref meta) => Some(meta.clone()),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
Ok(if let Some(meta) = meta {
|
||||||
|
self.bump();
|
||||||
|
(ast::Path::from_ident(meta.span, ast::Ident::with_empty_ctxt(meta.name)),
|
||||||
|
meta.node.tokens(meta.span))
|
||||||
|
} else {
|
||||||
|
(self.parse_path(PathStyle::Mod)?, self.parse_tokens())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse attributes that appear after the opening of an item. These should
|
/// Parse attributes that appear after the opening of an item. These should
|
||||||
/// be preceded by an exclamation mark, but we accept and warn about one
|
/// be preceded by an exclamation mark, but we accept and warn about one
|
||||||
/// terminated by a semicolon.
|
/// terminated by a semicolon.
|
||||||
|
|
|
@ -2644,6 +2644,17 @@ impl<'a> Parser<'a> {
|
||||||
Ok(tts)
|
Ok(tts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse_tokens(&mut self) -> TokenStream {
|
||||||
|
let mut result = Vec::new();
|
||||||
|
loop {
|
||||||
|
match self.token {
|
||||||
|
token::Eof | token::CloseDelim(..) => break,
|
||||||
|
_ => result.push(self.parse_token_tree().into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TokenStream::concat(result)
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse a prefix-unary-operator expr
|
/// Parse a prefix-unary-operator expr
|
||||||
pub fn parse_prefix_expr(&mut self,
|
pub fn parse_prefix_expr(&mut self,
|
||||||
already_parsed_attrs: Option<ThinVec<Attribute>>)
|
already_parsed_attrs: Option<ThinVec<Attribute>>)
|
||||||
|
|
|
@ -8,7 +8,5 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// compile-flags: -Z parse-only
|
|
||||||
|
|
||||||
#[doc = $not_there] //~ error: unexpected token: `$`
|
#[doc = $not_there] //~ error: unexpected token: `$`
|
||||||
fn main() { }
|
fn main() { }
|
|
@ -9,11 +9,11 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#[derive(Copy(Bad))]
|
#[derive(Copy(Bad))]
|
||||||
//~^ ERROR malformed `derive` entry
|
//~^ ERROR expected one of `)`, `,`, or `::`, found `(`
|
||||||
struct Test1;
|
struct Test1;
|
||||||
|
|
||||||
#[derive(Copy="bad")]
|
#[derive(Copy="bad")]
|
||||||
//~^ ERROR malformed `derive` entry
|
//~^ ERROR expected one of `)`, `,`, or `::`, found `=`
|
||||||
struct Test2;
|
struct Test2;
|
||||||
|
|
||||||
#[derive()]
|
#[derive()]
|
||||||
|
|
25
src/test/compile-fail/suffixed-literal-meta.rs
Normal file
25
src/test/compile-fail/suffixed-literal-meta.rs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![feature(attr_literals)]
|
||||||
|
|
||||||
|
#[path = 1usize] //~ ERROR: suffixed literals are not allowed in attributes
|
||||||
|
#[path = 1u8] //~ ERROR: suffixed literals are not allowed in attributes
|
||||||
|
#[path = 1u16] //~ ERROR: suffixed literals are not allowed in attributes
|
||||||
|
#[path = 1u32] //~ ERROR: suffixed literals are not allowed in attributes
|
||||||
|
#[path = 1u64] //~ ERROR: suffixed literals are not allowed in attributes
|
||||||
|
#[path = 1isize] //~ ERROR: suffixed literals are not allowed in attributes
|
||||||
|
#[path = 1i8] //~ ERROR: suffixed literals are not allowed in attributes
|
||||||
|
#[path = 1i16] //~ ERROR: suffixed literals are not allowed in attributes
|
||||||
|
#[path = 1i32] //~ ERROR: suffixed literals are not allowed in attributes
|
||||||
|
#[path = 1i64] //~ ERROR: suffixed literals are not allowed in attributes
|
||||||
|
#[path = 1.0f32] //~ ERROR: suffixed literals are not allowed in attributes
|
||||||
|
#[path = 1.0f64] //~ ERROR: suffixed literals are not allowed in attributes
|
||||||
|
fn main() { }
|
|
@ -8,10 +8,6 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// compile-flags: -Z parse-only
|
|
||||||
|
|
||||||
// error-pattern:expected one of `=` or `]`
|
|
||||||
|
|
||||||
// asterisk is bogus
|
// asterisk is bogus
|
||||||
#[attr*]
|
#[path*] //~ ERROR expected one of `(` or `=`
|
||||||
mod m {}
|
mod m {}
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
// compile-flags: -Z parse-only
|
|
||||||
|
|
||||||
#[foo = 1usize] //~ ERROR: suffixed literals are not allowed in attributes
|
|
||||||
#[foo = 1u8] //~ ERROR: suffixed literals are not allowed in attributes
|
|
||||||
#[foo = 1u16] //~ ERROR: suffixed literals are not allowed in attributes
|
|
||||||
#[foo = 1u32] //~ ERROR: suffixed literals are not allowed in attributes
|
|
||||||
#[foo = 1u64] //~ ERROR: suffixed literals are not allowed in attributes
|
|
||||||
#[foo = 1isize] //~ ERROR: suffixed literals are not allowed in attributes
|
|
||||||
#[foo = 1i8] //~ ERROR: suffixed literals are not allowed in attributes
|
|
||||||
#[foo = 1i16] //~ ERROR: suffixed literals are not allowed in attributes
|
|
||||||
#[foo = 1i32] //~ ERROR: suffixed literals are not allowed in attributes
|
|
||||||
#[foo = 1i64] //~ ERROR: suffixed literals are not allowed in attributes
|
|
||||||
#[foo = 1.0f32] //~ ERROR: suffixed literals are not allowed in attributes
|
|
||||||
#[foo = 1.0f64] //~ ERROR: suffixed literals are not allowed in attributes
|
|
||||||
fn main() { }
|
|
|
@ -2,7 +2,7 @@ error[E0536]: expected 1 cfg-pattern
|
||||||
--> $DIR/E0536.rs:11:7
|
--> $DIR/E0536.rs:11:7
|
||||||
|
|
|
|
||||||
11 | #[cfg(not())] //~ ERROR E0536
|
11 | #[cfg(not())] //~ ERROR E0536
|
||||||
| ^^^^^
|
| ^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ error[E0537]: invalid predicate `unknown`
|
||||||
--> $DIR/E0537.rs:11:7
|
--> $DIR/E0537.rs:11:7
|
||||||
|
|
|
|
||||||
11 | #[cfg(unknown())] //~ ERROR E0537
|
11 | #[cfg(unknown())] //~ ERROR E0537
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue