]> git.lizzy.rs Git - rust.git/commitdiff
Liberalize attributes.
authorJeffrey Seyfried <jeffrey.seyfried@gmail.com>
Wed, 8 Mar 2017 23:13:35 +0000 (23:13 +0000)
committerJeffrey Seyfried <jeffrey.seyfried@gmail.com>
Tue, 14 Mar 2017 04:39:21 +0000 (04:39 +0000)
18 files changed:
src/librustc_resolve/lib.rs
src/librustc_resolve/macros.rs
src/libsyntax/attr.rs
src/libsyntax/config.rs
src/libsyntax/ext/derive.rs
src/libsyntax/ext/expand.rs
src/libsyntax/ext/tt/macro_rules.rs
src/libsyntax/feature_gate.rs
src/libsyntax/parse/attr.rs
src/libsyntax/parse/parser.rs
src/test/compile-fail/macro-attribute.rs [new file with mode: 0644]
src/test/compile-fail/malformed-derive-entry.rs
src/test/compile-fail/suffixed-literal-meta.rs [new file with mode: 0644]
src/test/parse-fail/attr-bad-meta.rs
src/test/parse-fail/macro-attribute.rs [deleted file]
src/test/parse-fail/suffixed-literal-meta.rs [deleted file]
src/test/ui/span/E0536.stderr
src/test/ui/span/E0537.stderr

index c3e471650a3e183c254da6a229ba27a3fc8e5f43..bf7115abd4edd230fd7bc624431745c557ed6ce6 100644 (file)
@@ -1165,6 +1165,7 @@ pub struct Resolver<'a> {
 
     privacy_errors: Vec<PrivacyError<'a>>,
     ambiguity_errors: Vec<AmbiguityError<'a>>,
+    gated_errors: FxHashSet<Span>,
     disallowed_shadowing: Vec<&'a LegacyBinding<'a>>,
 
     arenas: &'a ResolverArenas<'a>,
@@ -1355,6 +1356,7 @@ pub fn new(session: &'a Session,
 
             privacy_errors: Vec::new(),
             ambiguity_errors: Vec::new(),
+            gated_errors: FxHashSet(),
             disallowed_shadowing: Vec::new(),
 
             arenas: arenas,
index 9e1dcd1bc35c497dc4ef71c8e17189fde08e4d73..67ce24efb3b1f4baa5ad55f4c112d2003cb886ad 100644 (file)
 use syntax::ext::tt::macro_rules;
 use syntax::feature_gate::{self, emit_feature_err, GateIssue};
 use syntax::fold::{self, Folder};
+use syntax::parse::parser::PathStyle;
+use syntax::parse::token::{self, Token};
 use syntax::ptr::P;
 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_pos::{Span, DUMMY_SP};
 
@@ -200,16 +202,22 @@ fn find_legacy_attr_invoc(&mut self, attrs: &mut Vec<ast::Attribute>)
             let name = unwrap_or!(attrs[i].name(), continue);
 
             if name == "derive" {
-                let mut traits = match attrs[i].meta_item_list() {
-                    Some(traits) => traits,
-                    _ => continue,
+                let result = attrs[i].parse_list(&self.session.parse_sess,
+                                                 |parser| parser.parse_path(PathStyle::Mod));
+                let mut traits = match result {
+                    Ok(traits) => traits,
+                    Err(mut e) => {
+                        e.cancel();
+                        continue
+                    }
                 };
 
                 for j in 0..traits.len() {
-                    let legacy_name = Symbol::intern(&match traits[j].word() {
-                        Some(..) => format!("derive_{}", traits[j].name().unwrap()),
-                        None => continue,
-                    });
+                    if traits[j].segments.len() > 1 {
+                        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) {
                         continue
                     }
@@ -218,7 +226,23 @@ fn find_legacy_attr_invoc(&mut self, attrs: &mut Vec<ast::Attribute>)
                     if traits.is_empty() {
                         attrs.remove(i);
                     } 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 {
                         path: ast::Path::from_ident(span, Ident::with_empty_ctxt(legacy_name)),
@@ -262,9 +286,8 @@ fn resolve_invoc_to_def(&mut self, invoc: &mut Invocation, scope: Mark, force: b
             InvocationKind::Bang { ref mac, .. } => {
                 return self.resolve_macro_to_def(scope, &mac.node.path, MacroKind::Bang, force);
             }
-            InvocationKind::Derive { name, span, .. } => {
-                let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name));
-                return self.resolve_macro_to_def(scope, &path, MacroKind::Derive, force);
+            InvocationKind::Derive { ref path, .. } => {
+                return self.resolve_macro_to_def(scope, path, MacroKind::Derive, force);
             }
         };
 
@@ -282,9 +305,8 @@ fn resolve_invoc_to_def(&mut self, invoc: &mut Invocation, scope: Mark, force: b
             1 => path.segments[0].identifier.name,
             _ => return Err(determinacy),
         };
-        for &(name, span) in traits {
-            let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name));
-            match self.resolve_macro(scope, &path, MacroKind::Derive, force) {
+        for path in traits {
+            match self.resolve_macro(scope, path, MacroKind::Derive, force) {
                 Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs) = *ext {
                     if inert_attrs.contains(&attr_name) {
                         // FIXME(jseyfried) Avoid `mem::replace` here.
@@ -327,7 +349,7 @@ fn resolve_macro_to_def(&mut self, scope: Mark, path: &ast::Path, kind: MacroKin
         self.current_module = invocation.module.get();
 
         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 feature = "use_extern_macros";
                 emit_feature_err(&self.session.parse_sess, feature, span, GateIssue::Language, msg);
index 68f1f690a62f084ed644801ee99bfe8b0fafee14..2f1efd6ad00ee07672483cb8a7139de0ee714304 100644 (file)
@@ -17,7 +17,7 @@
 use ast;
 use ast::{AttrId, Attribute, Name, Ident};
 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 syntax_pos::{Span, BytePos, DUMMY_SP};
 use errors::Handler;
@@ -299,6 +299,37 @@ pub fn meta(&self) -> Option<MetaItem> {
         })
     }
 
+    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> {
         if self.path.segments.len() > 1 {
             sess.span_diagnostic.span_err(self.path.span, "expected ident, found path");
@@ -306,7 +337,7 @@ pub fn parse_meta<'a>(&self, sess: &'a ParseSess) -> PResult<'a, MetaItem> {
 
         Ok(MetaItem {
             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,
         })
     }
@@ -985,6 +1016,10 @@ fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem>
     {
         let (mut span, name) = match tokens.next() {
             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,
         };
         let node = match MetaItemKind::from_tokens(tokens) {
@@ -1151,6 +1186,13 @@ fn from_token(token: Token) -> Option<LitKind> {
         match token {
             Token::Ident(ident) if ident.name == "true" => Some(LitKind::Bool(true)),
             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) => {
                 let (suffix_illegal, result) = parse::lit_token(lit, suf, None);
                 if suffix_illegal && suf.is_some() {
index 2591a5766693fb686861881a05944478fde783e1..ede8a33df6546db821b3681f93758aa362e43a29 100644 (file)
 use {fold, attr};
 use ast;
 use codemap::Spanned;
-use parse::ParseSess;
-use ptr::P;
+use parse::{token, ParseSess};
+use syntax_pos::Span;
 
+use ptr::P;
 use util::small_vector::SmallVector;
 
 /// A folder that strips out items that do not belong in the current configuration.
@@ -84,44 +85,33 @@ fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
             return Some(attr);
         }
 
-        let attr_list = match attr.meta_item_list() {
-            Some(attr_list) => attr_list,
-            None => {
-                let msg = "expected `#[cfg_attr(<cfg pattern>, <attr>)]`";
-                self.sess.span_diagnostic.span_err(attr.span, msg);
-                return None;
-            }
-        };
-
-        let (cfg, mi) = match (attr_list.len(), attr_list.get(0), attr_list.get(1)) {
-            (2, Some(cfg), Some(mi)) => (cfg, mi),
-            _ => {
-                let msg = "expected `#[cfg_attr(<cfg pattern>, <attr>)]`";
-                self.sess.span_diagnostic.span_err(attr.span, msg);
+        let (cfg, path, tokens, span) = match attr.parse(self.sess, |parser| {
+            parser.expect(&token::OpenDelim(token::Paren))?;
+            let cfg = parser.parse_meta_item()?;
+            parser.expect(&token::Comma)?;
+            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;
             }
         };
 
-        use attr::cfg_matches;
-        match (cfg.meta_item(), mi.meta_item()) {
-            (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
-            }
+        if attr::cfg_matches(&cfg, self.sess, self.features) {
+            self.process_cfg_attr(ast::Attribute {
+                id: attr::mk_attr_id(),
+                style: attr.style,
+                path: path,
+                tokens: tokens,
+                is_sugared_doc: false,
+                span: span,
+            })
+        } else {
+            None
         }
     }
 
@@ -133,10 +123,12 @@ pub fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool {
                 return false;
             }
 
-            let mis = attr.meta_item_list();
-            let mis = match mis {
-                Some(ref mis) if is_cfg(&attr) => mis,
-                _ => return true
+            let mis = if !is_cfg(&attr) {
+                return true;
+            } else if let Some(mis) = attr.meta_item_list() {
+                mis
+            } else {
+                return true;
             };
 
             if mis.len() != 1 {
index 5b253635f257e5e5d37c7cb16d8d430d840c508d..1569d9f540b8ebf679eb69b92f14d750d77545f3 100644 (file)
 use {ast, codemap};
 use ext::base::ExtCtxt;
 use ext::build::AstBuilder;
+use parse::parser::PathStyle;
 use symbol::Symbol;
 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();
     attrs.retain(|attr| {
         if attr.path != "derive" {
             return true;
         }
 
-        if attr.value_str().is_some() {
-            cx.span_err(attr.span, "unexpected value in `derive`");
-            return false;
-        }
-
-        let traits = attr.meta_item_list().unwrap_or_else(Vec::new);
-        if traits.is_empty() {
-            cx.span_warn(attr.span, "empty trait list in `derive`");
-            return false;
-        }
-
-        for titem in traits {
-            if titem.word().is_none() {
-                cx.span_err(titem.span, "malformed `derive` entry");
-                return false;
+        match attr.parse_list(cx.parse_sess, |parser| parser.parse_path(PathStyle::Mod)) {
+            Ok(ref traits) if traits.is_empty() => {
+                cx.span_warn(attr.span, "empty trait list in `derive`");
+                false
+            }
+            Ok(traits) => {
+                result.extend(traits);
+                true
+            }
+            Err(mut e) => {
+                e.emit();
+                false
             }
-            result.push((titem.name().unwrap(), titem.span));
         }
-
-        true
     });
     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) {
-        Some(&(_, span)) => span,
+        Some(path) => path.span,
         None => return item,
     };
 
     item.map_attrs(|mut attrs| {
-        if traits.iter().any(|&(name, _)| name == "PartialEq") &&
-           traits.iter().any(|&(name, _)| name == "Eq") {
+        if traits.iter().any(|path| *path == "PartialEq") &&
+           traits.iter().any(|path| *path == "Eq") {
             let span = allow_unstable(cx, span, "derive(PartialEq, Eq)");
             let meta = cx.meta_word(span, Symbol::intern("structural_match"));
             attrs.push(cx.attribute(span, meta));
         }
-        if traits.iter().any(|&(name, _)| name == "Copy") &&
-           traits.iter().any(|&(name, _)| name == "Clone") {
+        if traits.iter().any(|path| *path == "Copy") &&
+           traits.iter().any(|path| *path == "Clone") {
             let span = allow_unstable(cx, span, "derive(Copy, Clone)");
             let meta = cx.meta_word(span, Symbol::intern("rustc_copy_clone_marker"));
             attrs.push(cx.attribute(span, meta));
index c1095d34456820e9d60974a8fbcb611f8e83e46c..c1816582bc6ca2418c8bc361f841d4c77b35a17a 100644 (file)
@@ -8,8 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ast::{self, Block, Ident, PatKind};
-use ast::{Name, MacStmtStyle, StmtKind, ItemKind};
+use ast::{self, Block, Ident, PatKind, Path};
+use ast::{MacStmtStyle, StmtKind, ItemKind};
 use attr::{self, HasAttrs};
 use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
 use config::{is_test_or_bench, StripUnconfigured};
@@ -27,7 +27,7 @@
 use std_inject;
 use symbol::Symbol;
 use symbol::keywords;
-use syntax_pos::{self, Span, ExpnId};
+use syntax_pos::{Span, ExpnId, DUMMY_SP};
 use tokenstream::TokenStream;
 use util::small_vector::SmallVector;
 use visit::Visitor;
@@ -165,12 +165,11 @@ pub enum InvocationKind {
     },
     Attr {
         attr: Option<ast::Attribute>,
-        traits: Vec<(Symbol, Span)>,
+        traits: Vec<Path>,
         item: Annotatable,
     },
     Derive {
-        name: Symbol,
-        span: Span,
+        path: Path,
         item: Annotatable,
     },
 }
@@ -180,8 +179,8 @@ fn span(&self) -> Span {
         match self.kind {
             InvocationKind::Bang { span, .. } => span,
             InvocationKind::Attr { attr: Some(ref attr), .. } => attr.span,
-            InvocationKind::Attr { attr: None, .. } => syntax_pos::DUMMY_SP,
-            InvocationKind::Derive { span, .. } => span,
+            InvocationKind::Attr { attr: None, .. } => DUMMY_SP,
+            InvocationKind::Derive { ref path, .. } => path.span,
         }
     }
 }
@@ -277,12 +276,11 @@ fn expand(&mut self, expansion: Expansion) -> Expansion {
                         add_derived_markers(&mut self.cx, &traits, item.clone());
                     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();
                         derives.push(mark);
-                        let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name));
                         let item = match self.cx.resolver.resolve_macro(
-                                Mark::root(), &path, MacroKind::Derive, false) {
+                                Mark::root(), path, MacroKind::Derive, false) {
                             Ok(ext) => match *ext {
                                 SyntaxExtension::BuiltinDerive(..) => item_with_markers.clone(),
                                 _ => item.clone(),
@@ -290,7 +288,7 @@ fn expand(&mut self, expansion: Expansion) -> Expansion {
                             _ => item.clone(),
                         };
                         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_data: ExpansionData {
                                 mark: mark,
@@ -380,11 +378,10 @@ fn expand_attr_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) ->
         };
 
         attr::mark_used(&attr);
-        let name = attr.path.segments[0].identifier.name;
         self.cx.bt_push(ExpnInfo {
             call_site: attr.span,
             callee: NameAndSpan {
-                format: MacroAttribute(name),
+                format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))),
                 span: Some(attr.span),
                 allow_internal_unstable: false,
             }
@@ -419,14 +416,14 @@ fn expand_attr_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) ->
                 };
 
                 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(..) => {
-                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)
             }
             _ => {
-                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);
                 kind.dummy(attr.span)
             }
@@ -442,7 +439,6 @@ fn expand_bang_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) ->
         };
         let path = &mac.node.path;
 
-        let extname = path.segments.last().unwrap().identifier.name;
         let ident = ident.unwrap_or(keywords::Invalid.ident());
         let marked_tts =
             noop_fold_tts(mac.node.stream(), &mut Marker { mark: mark, expn_id: None });
@@ -450,7 +446,7 @@ fn expand_bang_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) ->
             NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
                 if ident.name != keywords::Invalid.name() {
                     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);
                     return kind.dummy(span);
                 }
@@ -458,7 +454,7 @@ fn expand_bang_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) ->
                 self.cx.bt_push(ExpnInfo {
                     call_site: span,
                     callee: NameAndSpan {
-                        format: MacroBang(extname),
+                        format: MacroBang(Symbol::intern(&format!("{}", path))),
                         span: exp_span,
                         allow_internal_unstable: allow_internal_unstable,
                     },
@@ -470,14 +466,14 @@ fn expand_bang_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) ->
             IdentTT(ref expander, tt_span, allow_internal_unstable) => {
                 if ident.name == keywords::Invalid.name() {
                     self.cx.span_err(path.span,
-                                    &format!("macro {}! expects an ident argument", extname));
+                                    &format!("macro {}! expects an ident argument", path));
                     return kind.dummy(span);
                 };
 
                 self.cx.bt_push(ExpnInfo {
                     call_site: span,
                     callee: NameAndSpan {
-                        format: MacroBang(extname),
+                        format: MacroBang(Symbol::intern(&format!("{}", path))),
                         span: tt_span,
                         allow_internal_unstable: allow_internal_unstable,
                     }
@@ -489,19 +485,19 @@ fn expand_bang_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) ->
 
             MultiDecorator(..) | MultiModifier(..) | SyntaxExtension::AttrProcMacro(..) => {
                 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);
             }
 
             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);
             }
 
             SyntaxExtension::ProcMacro(ref expandfun) => {
                 if ident.name != keywords::Invalid.name() {
                     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);
                     return kind.dummy(span);
                 }
@@ -509,7 +505,7 @@ fn expand_bang_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) ->
                 self.cx.bt_push(ExpnInfo {
                     call_site: span,
                     callee: NameAndSpan {
-                        format: MacroBang(extname),
+                        format: MacroBang(Symbol::intern(&format!("{}", path))),
                         // FIXME procedural macros do not have proper span info
                         // yet, when they do, we should use it here.
                         span: None,
@@ -519,7 +515,7 @@ fn expand_bang_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) ->
                 });
 
                 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 @@ fn expand_bang_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) ->
     /// Expand a derive invocation. Returns the result of expansion.
     fn expand_derive_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Expansion {
         let Invocation { expansion_kind: kind, .. } = invoc;
-        let (name, span, item) = match invoc.kind {
-            InvocationKind::Derive { name, span, item } => (name, span, item),
+        let (path, item) = match invoc.kind {
+            InvocationKind::Derive { path, item } => (path, item),
             _ => unreachable!(),
         };
 
-        let mitem = ast::MetaItem { name: name, span: span, node: ast::MetaItemKind::Word };
-        let pretty_name = Symbol::intern(&format!("derive({})", name));
+        let pretty_name = Symbol::intern(&format!("derive({})", path));
+        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 {
             call_site: span,
             callee: NameAndSpan {
                 format: MacroAttribute(pretty_name),
-                span: Some(span),
+                span: None,
                 allow_internal_unstable: false,
             }
         });
@@ -571,7 +572,12 @@ fn expand_derive_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -
                     }),
                     ..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) => {
                 let span = Span {
@@ -586,20 +592,18 @@ fn expand_derive_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -
                     ..span
                 };
                 let mut items = Vec::new();
-                func(self.cx, span, &mitem, &item, &mut |a| {
-                    items.push(a)
-                });
+                func(self.cx, span, &attr.meta().unwrap(), &item, &mut |a| items.push(a));
                 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);
                 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 {
         let mut parser = self.cx.new_parser_from_tts(&toks.into_trees().collect::<Vec<_>>());
         let expansion = match parser.parse_expansion(kind, false) {
@@ -609,7 +613,7 @@ fn parse_expansion(&mut self, toks: TokenStream, kind: ExpansionKind, name: Name
                 return kind.dummy(span);
             }
         };
-        parser.ensure_complete_parse(name, kind.name(), span);
+        parser.ensure_complete_parse(path, kind.name(), span);
         // FIXME better span info
         expansion.fold_with(&mut ChangeSpan { span: span })
     }
@@ -658,14 +662,14 @@ pub fn parse_expansion(&mut self, kind: ExpansionKind, macro_legacy_warnings: bo
         })
     }
 
-    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 {
             let msg = format!("macro expansion ignores token `{}` and any following",
                               self.this_token_to_string());
             let mut err = self.diagnostic().struct_span_err(self.span, &msg);
             let msg = format!("caused by the macro expansion here; the usage \
                                of `{}!` is likely invalid in {} context",
-                               macro_name, kind_name);
+                               macro_path, kind_name);
             err.span_note(span, &msg).emit();
         }
     }
@@ -708,20 +712,20 @@ fn collect_bang(&mut self, mac: ast::Mac, span: Span, kind: ExpansionKind) -> Ex
 
     fn collect_attr(&mut self,
                     attr: Option<ast::Attribute>,
-                    traits: Vec<(Symbol, Span)>,
+                    traits: Vec<Path>,
                     item: Annotatable,
                     kind: ExpansionKind)
                     -> Expansion {
         if !traits.is_empty() &&
            (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));
         }
         self.collect(kind, InvocationKind::Attr { attr: attr, traits: traits, item: item })
     }
 
     // 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,
     {
         let (mut attr, mut traits) = (None, Vec::new());
@@ -900,7 +904,7 @@ fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
                 // 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`).
                 // 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 let Some(path) = attr::first_attr_value_str_by_name(&item.attrs, "path") {
index 7aa1230f9aeea9a9eb664be80fed382307e9039a..021c5398a4200459218a8f94d78df25ed77b6502 100644 (file)
@@ -51,7 +51,8 @@ pub fn make(mut self: Box<ParserAnyMacro<'a>>, kind: ExpansionKind) -> Expansion
         }
 
         // 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
     }
 }
index 2c3ad98a6be63c7db4e2f358636e19fce93be0e4..05e7b0f9aa4da8b38d5eb7ad4c23a111054be5df 100644 (file)
@@ -1096,6 +1096,10 @@ fn visit_attribute(&mut self, attr: &ast::Attribute) {
             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));
         if contains_novel_literal(&meta) {
             gate_feature_post!(&self, attr_literals, attr.span,
index 272cff7ad34b2818b82a6dff1f49ea86da0da525..53106214fa3107f53fef6b85d608e895ca1eba39 100644 (file)
@@ -14,8 +14,9 @@
 use codemap::spanned;
 use parse::common::SeqSep;
 use parse::PResult;
-use parse::token;
-use parse::parser::{Parser, TokenType};
+use parse::token::{self, Nonterminal};
+use parse::parser::{Parser, TokenType, PathStyle};
+use tokenstream::TokenStream;
 
 #[derive(PartialEq, Eq, Debug)]
 enum InnerAttributeParsePolicy<'a> {
@@ -91,7 +92,7 @@ fn parse_attribute_with_inner_parse_policy(&mut self,
         debug!("parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}",
                inner_parse_policy,
                self.token);
-        let (span, value, mut style) = match self.token {
+        let (span, path, tokens, mut style) = match self.token {
             token::Pound => {
                 let lo = self.span.lo;
                 self.bump();
@@ -119,11 +120,11 @@ fn parse_attribute_with_inner_parse_policy(&mut self,
                 };
 
                 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))?;
                 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();
@@ -143,13 +144,30 @@ fn parse_attribute_with_inner_parse_policy(&mut self,
         Ok(ast::Attribute {
             id: attr::mk_attr_id(),
             style: style,
-            path: ast::Path::from_ident(value.span, ast::Ident::with_empty_ctxt(value.name)),
-            tokens: value.node.tokens(value.span),
+            path: path,
+            tokens: tokens,
             is_sugared_doc: false,
             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
     /// be preceded by an exclamation mark, but we accept and warn about one
     /// terminated by a semicolon.
index ed512b899877d8996434efc8d33b8d0265544e30..308876fed56dc8d03ed5e2d036c5f8762c6d5703 100644 (file)
@@ -2644,6 +2644,17 @@ pub fn parse_all_token_trees(&mut self) -> PResult<'a, Vec<TokenTree>> {
         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
     pub fn parse_prefix_expr(&mut self,
                              already_parsed_attrs: Option<ThinVec<Attribute>>)
diff --git a/src/test/compile-fail/macro-attribute.rs b/src/test/compile-fail/macro-attribute.rs
new file mode 100644 (file)
index 0000000..52f867f
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright 2014 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.
+
+#[doc = $not_there] //~ error: unexpected token: `$`
+fn main() { }
index 62dbc21495a5405a0ff0ee2bd4221c86c4c32fdc..ac000628f2b0498331d4ceb729fe3e40cdaa4f60 100644 (file)
@@ -9,11 +9,11 @@
 // except according to those terms.
 
 #[derive(Copy(Bad))]
-//~^ ERROR malformed `derive` entry
+//~^ ERROR expected one of `)`, `,`, or `::`, found `(`
 struct Test1;
 
 #[derive(Copy="bad")]
-//~^ ERROR malformed `derive` entry
+//~^ ERROR expected one of `)`, `,`, or `::`, found `=`
 struct Test2;
 
 #[derive()]
diff --git a/src/test/compile-fail/suffixed-literal-meta.rs b/src/test/compile-fail/suffixed-literal-meta.rs
new file mode 100644 (file)
index 0000000..bf55b7b
--- /dev/null
@@ -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() { }
index 092adbf29e340cd52394c00e169fdb4dd746544f..d57a813311b5ab509f35fe980da31c47624fbdf2 100644 (file)
@@ -8,10 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags: -Z parse-only
-
-// error-pattern:expected one of `=` or `]`
-
 // asterisk is bogus
-#[attr*]
+#[path*] //~ ERROR expected one of `(` or `=`
 mod m {}
diff --git a/src/test/parse-fail/macro-attribute.rs b/src/test/parse-fail/macro-attribute.rs
deleted file mode 100644 (file)
index 18add7d..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2014 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
-
-#[doc = $not_there] //~ error: unexpected token: `$`
-fn main() { }
diff --git a/src/test/parse-fail/suffixed-literal-meta.rs b/src/test/parse-fail/suffixed-literal-meta.rs
deleted file mode 100644 (file)
index 0e2840c..0000000
+++ /dev/null
@@ -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() { }
index c33b89953e27461f965c88f487ebf2879d59565c..b2da0c6a296d8fc5119d4f68560f799f9947408d 100644 (file)
@@ -2,7 +2,7 @@ error[E0536]: expected 1 cfg-pattern
   --> $DIR/E0536.rs:11:7
    |
 11 | #[cfg(not())] //~ ERROR E0536
-   |       ^^^^^
+   |       ^^^
 
 error: aborting due to previous error
 
index 9d66ddbaae317dbc0592340dedace69262bbbbdd..29873943f444d8e65a7fc59f27af530744919307 100644 (file)
@@ -2,7 +2,7 @@ error[E0537]: invalid predicate `unknown`
   --> $DIR/E0537.rs:11:7
    |
 11 | #[cfg(unknown())] //~ ERROR E0537
-   |       ^^^^^^^^^
+   |       ^^^^^^^
 
 error: aborting due to previous error