// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use ast::{Block, Crate, DeclLocal, ExprMac, PatMac};
+use ast::{Block, Crate, DeclLocal, PatMac};
use ast::{Local, Ident, Mac_, Name};
use ast::{ItemMac, MacStmtWithSemicolon, Mrk, Stmt, StmtDecl, StmtMac};
use ast::{StmtExpr, StmtSemi};
use ext::mtwt;
use ext::build::AstBuilder;
use attr;
-use attr::AttrMetaMethods;
+use attr::{AttrMetaMethods, WithAttrs};
use codemap;
use codemap::{Span, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
use ext::base::*;
-use feature_gate::{self, Features, GatedCfg};
+use feature_gate::{self, Features};
use fold;
use fold::*;
+use util::move_map::MoveMap;
use parse;
use parse::token::{fresh_mark, fresh_name, intern};
use ptr::P;
pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
let expr_span = e.span;
- return e.and_then(|ast::Expr {id, node, span}| match node {
+ return e.and_then(|ast::Expr {id, node, span, attrs}| match node {
// expr_mac should really be expr_ext or something; it's the
// entry-point for all syntax extensions.
ast::ExprMac(mac) => {
+
+ // Assert that we drop any macro attributes on the floor here
+ drop(attrs);
+
let expanded_expr = match expand_mac_invoc(mac, span,
|r| r.make_expr(),
mark_expr, fld) {
id: ast::DUMMY_NODE_ID,
node: e.node,
span: span,
+ attrs: e.attrs,
})
}
let placer = fld.fold_expr(placer);
let value_expr = fld.fold_expr(value_expr);
fld.cx.expr(span, ast::ExprInPlace(placer, value_expr))
+ .with_attrs(fold_thin_attrs(attrs, fld))
}
ast::ExprWhile(cond, body, opt_ident) => {
let cond = fld.fold_expr(cond);
let (body, opt_ident) = expand_loop_block(body, opt_ident, fld);
fld.cx.expr(span, ast::ExprWhile(cond, body, opt_ident))
+ .with_attrs(fold_thin_attrs(attrs, fld))
}
ast::ExprWhileLet(pat, expr, body, opt_ident) => {
assert!(rewritten_pats.len() == 1);
fld.cx.expr(span, ast::ExprWhileLet(rewritten_pats.remove(0), expr, body, opt_ident))
+ .with_attrs(fold_thin_attrs(attrs, fld))
}
ast::ExprLoop(loop_block, opt_ident) => {
let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld);
fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident))
+ .with_attrs(fold_thin_attrs(attrs, fld))
}
ast::ExprForLoop(pat, head, body, opt_ident) => {
let head = fld.fold_expr(head);
fld.cx.expr(span, ast::ExprForLoop(rewritten_pats.remove(0), head, body, opt_ident))
+ .with_attrs(fold_thin_attrs(attrs, fld))
}
ast::ExprIfLet(pat, sub_expr, body, else_opt) => {
let else_opt = else_opt.map(|else_opt| fld.fold_expr(else_opt));
let sub_expr = fld.fold_expr(sub_expr);
fld.cx.expr(span, ast::ExprIfLet(rewritten_pats.remove(0), sub_expr, body, else_opt))
+ .with_attrs(fold_thin_attrs(attrs, fld))
}
ast::ExprClosure(capture_clause, fn_decl, block) => {
let new_node = ast::ExprClosure(capture_clause,
rewritten_fn_decl,
rewritten_block);
- P(ast::Expr{id:id, node: new_node, span: fld.new_span(span)})
+ P(ast::Expr{id:id, node: new_node, span: fld.new_span(span),
+ attrs: fold_thin_attrs(attrs, fld)})
}
_ => {
P(noop_fold_expr(ast::Expr {
id: id,
node: node,
- span: span
+ span: span,
+ attrs: attrs
}, fld))
}
});
let extname = pth.segments[0].identifier.name;
match fld.cx.syntax_env.find(extname) {
None => {
- fld.cx.span_err(
+ let mut err = fld.cx.struct_span_err(
pth.span,
&format!("macro undefined: '{}!'",
&extname));
- fld.cx.suggest_macro_name(&extname.as_str(), pth.span);
+ fld.cx.suggest_macro_name(&extname.as_str(), pth.span, &mut err);
+ err.emit();
// let compilation continue
None
for attr in attrs {
let mut is_use = attr.check_name("macro_use");
if attr.check_name("macro_escape") {
- fld.cx.span_warn(attr.span, "macro_escape is a deprecated synonym for macro_use");
+ let mut err =
+ fld.cx.struct_span_warn(attr.span,
+ "macro_escape is a deprecated synonym for macro_use");
is_use = true;
if let ast::AttrStyle::Inner = attr.node.style {
- fld.cx.fileline_help(attr.span, "consider an outer attribute, \
- #[macro_use] mod ...");
+ err.fileline_help(attr.span, "consider an outer attribute, \
+ #[macro_use] mod ...").emit();
+ } else {
+ err.emit();
}
};
/// Expand a stmt
fn expand_stmt(stmt: P<Stmt>, fld: &mut MacroExpander) -> SmallVector<P<Stmt>> {
let stmt = stmt.and_then(|stmt| stmt);
- let (mac, style) = match stmt.node {
- StmtMac(mac, style) => (mac, style),
+ let (mac, style, attrs) = match stmt.node {
+ StmtMac(mac, style, attrs) => (mac, style, attrs),
_ => return expand_non_macro_stmt(stmt, fld)
};
+ // Assert that we drop any macro attributes on the floor here
+ drop(attrs);
+
let maybe_new_items =
expand_mac_invoc(mac.and_then(|m| m), stmt.span,
|r| r.make_stmts(),
StmtDecl(decl, node_id) => decl.and_then(|Spanned {node: decl, span}| match decl {
DeclLocal(local) => {
// take it apart:
- let rewritten_local = local.map(|Local {id, pat, ty, init, span}| {
+ let rewritten_local = local.map(|Local {id, pat, ty, init, span, attrs}| {
// expand the ty since TyFixedLengthVec contains an Expr
// and thus may have a macro use
let expanded_ty = ty.map(|t| fld.fold_ty(t));
pat: rewritten_pat,
// also, don't forget to expand the init:
init: init.map(|e| fld.fold_expr(e)),
- span: span
+ span: span,
+ attrs: fold::fold_thin_attrs(attrs, fld),
}
});
SmallVector::one(P(Spanned {
}
}
-pub fn expand_crate<'feat>(parse_sess: &parse::ParseSess,
- cfg: ExpansionConfig<'feat>,
- // these are the macros being imported to this crate:
- imported_macros: Vec<ast::MacroDef>,
- user_exts: Vec<NamedSyntaxExtension>,
- feature_gated_cfgs: &mut Vec<GatedCfg>,
- c: Crate) -> (Crate, HashSet<Name>) {
- let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg,
- feature_gated_cfgs);
+pub fn expand_crate(mut cx: ExtCtxt,
+ // these are the macros being imported to this crate:
+ imported_macros: Vec<ast::MacroDef>,
+ user_exts: Vec<NamedSyntaxExtension>,
+ c: Crate) -> (Crate, HashSet<Name>) {
if std_inject::no_core(&c) {
cx.crate_root = None;
} else if std_inject::no_std(&c) {
let mut ret = expander.fold_crate(c);
ret.exported_macros = expander.cx.exported_macros.clone();
- parse_sess.span_diagnostic.handler().abort_if_errors();
+ cx.parse_sess.span_diagnostic.abort_if_errors();
ret
};
return (ret, cx.syntax_env.names);
use ast;
use ast::Name;
use codemap;
+ use ext::base::ExtCtxt;
use ext::mtwt;
use fold::Folder;
use parse;
src,
Vec::new(), &sess);
// should fail:
- expand_crate(&sess,test_ecfg(),vec!(),vec!(), &mut vec![], crate_ast);
+ let mut gated_cfgs = vec![];
+ let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut gated_cfgs);
+ expand_crate(ecx, vec![], vec![], crate_ast);
}
// make sure that macros can't escape modules
"<test>".to_string(),
src,
Vec::new(), &sess);
- expand_crate(&sess,test_ecfg(),vec!(),vec!(), &mut vec![], crate_ast);
+ let mut gated_cfgs = vec![];
+ let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut gated_cfgs);
+ expand_crate(ecx, vec![], vec![], crate_ast);
}
// macro_use modules should allow macros to escape
"<test>".to_string(),
src,
Vec::new(), &sess);
- expand_crate(&sess, test_ecfg(), vec!(), vec!(), &mut vec![], crate_ast);
+ let mut gated_cfgs = vec![];
+ let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut gated_cfgs);
+ expand_crate(ecx, vec![], vec![], crate_ast);
}
fn expand_crate_str(crate_str: String) -> ast::Crate {
let ps = parse::ParseSess::new();
let crate_ast = panictry!(string_to_parser(&ps, crate_str).parse_crate_mod());
// the cfg argument actually does matter, here...
- expand_crate(&ps,test_ecfg(),vec!(),vec!(), &mut vec![], crate_ast).0
+ let mut gated_cfgs = vec![];
+ let ecx = ExtCtxt::new(&ps, vec![], test_ecfg(), &mut gated_cfgs);
+ expand_crate(ecx, vec![], vec![], crate_ast).0
}
// find the pat_ident paths in a crate