about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorJeffrey Seyfried <jeffrey.seyfried@gmail.com>2016-08-27 05:27:59 +0000
committerJeffrey Seyfried <jeffrey.seyfried@gmail.com>2016-09-05 04:53:20 +0000
commitde2e67836e23405e5bdc27cefa510fa562c5298f (patch)
tree750f07f824dcf6bf917145c029023146a5b0d9c2 /src/libsyntax
parent9b3bc7a9e9e35537823bc2a10fc078c1222ee7fd (diff)
downloadrust-de2e67836e23405e5bdc27cefa510fa562c5298f.tar.gz
rust-de2e67836e23405e5bdc27cefa510fa562c5298f.zip
Add `Invocation` and `Expansion`, remove `MacroGenerable`.
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ext/expand.rs452
1 files changed, 240 insertions, 212 deletions
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 92d053fd21b..485bd3ce10b 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -30,249 +30,230 @@ use std_inject;
 
 use std::path::PathBuf;
 
-// A trait for AST nodes and AST node lists into which macro invocations may expand.
-trait MacroGenerable: Sized {
-    // Expand the given MacResult using its appropriate `make_*` method.
-    fn make_with<'a>(result: Box<MacResult + 'a>) -> Option<Self>;
-
-    // Fold this node or list of nodes using the given folder.
-    fn fold_with<F: Folder>(self, folder: &mut F) -> Self;
-    fn visit_with<V: Visitor>(&self, visitor: &mut V);
+macro_rules! expansions {
+    ($($kind:ident: $ty:ty, $kind_name:expr, .$make:ident,
+            $(.$fold:ident)*  $(lift .$fold_elt:ident)*,
+            $(.$visit:ident)* $(lift .$visit_elt:ident)*;)*) => {
+        #[derive(Copy, Clone)]
+        enum ExpansionKind { OptExpr, $( $kind, )*  }
+        enum Expansion { OptExpr(Option<P<ast::Expr>>), $( $kind($ty), )* }
+
+        impl ExpansionKind {
+            fn name(self) -> &'static str {
+                match self {
+                    ExpansionKind::OptExpr => "expression",
+                    $( ExpansionKind::$kind => $kind_name, )*
+                }
+            }
 
-    // The user-friendly name of the node type (e.g. "expression", "item", etc.) for diagnostics.
-    fn kind_name() -> &'static str;
+            fn make_from<'a>(self, result: Box<MacResult + 'a>) -> Option<Expansion> {
+                match self {
+                    ExpansionKind::OptExpr => result.make_expr().map(Some).map(Expansion::OptExpr),
+                    $( ExpansionKind::$kind => result.$make().map(Expansion::$kind), )*
+                }
+            }
+        }
 
-    // Return a placeholder expansion to allow compilation to continue after an erroring expansion.
-    fn dummy(span: Span) -> Self {
-        Self::make_with(DummyResult::any(span)).unwrap()
-    }
-}
+        impl Expansion {
+            fn make_opt_expr(self) -> Option<P<ast::Expr>> {
+                match self {
+                    Expansion::OptExpr(expr) => expr,
+                    _ => panic!("Expansion::make_* called on the wrong kind of expansion"),
+                }
+            }
+            $( fn $make(self) -> $ty {
+                match self {
+                    Expansion::$kind(ast) => ast,
+                    _ => panic!("Expansion::make_* called on the wrong kind of expansion"),
+                }
+            } )*
 
-macro_rules! impl_macro_generable {
-    ($($ty:ty: $kind_name:expr, .$make:ident,
-               $(.$fold:ident)*  $(lift .$fold_elt:ident)*,
-               $(.$visit:ident)* $(lift .$visit_elt:ident)*;)*) => { $(
-        impl MacroGenerable for $ty {
-            fn kind_name() -> &'static str { $kind_name }
-            fn make_with<'a>(result: Box<MacResult + 'a>) -> Option<Self> { result.$make() }
             fn fold_with<F: Folder>(self, folder: &mut F) -> Self {
-                $( folder.$fold(self) )*
-                $( self.into_iter().flat_map(|item| folder. $fold_elt (item)).collect() )*
+                use self::Expansion::*;
+                match self {
+                    OptExpr(expr) => OptExpr(expr.and_then(|expr| folder.fold_opt_expr(expr))),
+                    $($( $kind(ast) => $kind(folder.$fold(ast)), )*)*
+                    $($( $kind(ast) => {
+                        $kind(ast.into_iter().flat_map(|ast| folder.$fold_elt(ast)).collect())
+                    }, )*)*
+                }
             }
+
             fn visit_with<V: Visitor>(&self, visitor: &mut V) {
-                $( visitor.$visit(self) )*
-                $( for item in self.as_slice() { visitor. $visit_elt (item) } )*
+                match *self {
+                    Expansion::OptExpr(Some(ref expr)) => visitor.visit_expr(expr),
+                    $($( Expansion::$kind(ref ast) => visitor.$visit(ast), )*)*
+                    $($( Expansion::$kind(ref ast) => for ast in ast.as_slice() {
+                        visitor.$visit_elt(ast);
+                    }, )*)*
+                    _ => {}
+                }
             }
         }
-    )* }
+    }
 }
 
-impl_macro_generable! {
-    P<ast::Expr>: "expression", .make_expr, .fold_expr, .visit_expr;
-    P<ast::Pat>:  "pattern",    .make_pat,  .fold_pat,  .visit_pat;
-    P<ast::Ty>:   "type",       .make_ty,   .fold_ty,   .visit_ty;
-    SmallVector<ast::Stmt>: "statement", .make_stmts, lift .fold_stmt, lift .visit_stmt;
-    SmallVector<P<ast::Item>>: "item",   .make_items, lift .fold_item, lift .visit_item;
-    SmallVector<ast::TraitItem>:
+expansions! {
+    Expr: P<ast::Expr>, "expression", .make_expr, .fold_expr, .visit_expr;
+    Pat: P<ast::Pat>,   "pattern",    .make_pat,  .fold_pat,  .visit_pat;
+    Ty: P<ast::Ty>,     "type",       .make_ty,   .fold_ty,   .visit_ty;
+    Stmts: SmallVector<ast::Stmt>, "statement", .make_stmts, lift .fold_stmt, lift .visit_stmt;
+    Items: SmallVector<P<ast::Item>>, "item",   .make_items, lift .fold_item, lift .visit_item;
+    TraitItems: SmallVector<ast::TraitItem>,
         "trait item", .make_trait_items, lift .fold_trait_item, lift .visit_trait_item;
-    SmallVector<ast::ImplItem>:
+    ImplItems: SmallVector<ast::ImplItem>,
         "impl item",  .make_impl_items,  lift .fold_impl_item,  lift .visit_impl_item;
 }
 
-impl MacroGenerable for Option<P<ast::Expr>> {
-    fn kind_name() -> &'static str { "expression" }
-    fn make_with<'a>(result: Box<MacResult + 'a>) -> Option<Self> {
-        result.make_expr().map(Some)
-    }
-    fn fold_with<F: Folder>(self, folder: &mut F) -> Self {
-        self.and_then(|expr| folder.fold_opt_expr(expr))
-    }
-    fn visit_with<V: Visitor>(&self, visitor: &mut V) {
-        self.as_ref().map(|expr| visitor.visit_expr(expr));
+impl ExpansionKind {
+    fn dummy(self, span: Span) -> Expansion {
+        self.make_from(DummyResult::any(span)).unwrap()
     }
 }
 
-pub fn expand_expr(expr: ast::Expr, fld: &mut MacroExpander) -> P<ast::Expr> {
-    match expr.node {
-        // expr_mac should really be expr_ext or something; it's the
-        // entry-point for all syntax extensions.
-        ast::ExprKind::Mac(mac) => {
-            return expand_mac_invoc(mac, None, expr.attrs.into(), expr.span, fld);
-        }
-        _ => P(noop_fold_expr(expr, fld)),
-    }
+pub struct Invocation {
+    span: Span,
+    attrs: Vec<ast::Attribute>,
+    mac: ast::Mac,
+    ident: Option<Ident>,
+    mark: Mark,
+    kind: ExpansionKind,
 }
 
-struct MacroScopePlaceholder;
-impl MacResult for MacroScopePlaceholder {
-    fn make_items(self: Box<Self>) -> Option<SmallVector<P<ast::Item>>> {
-        Some(SmallVector::one(P(ast::Item {
-            ident: keywords::Invalid.ident(),
-            attrs: Vec::new(),
-            id: ast::DUMMY_NODE_ID,
-            node: ast::ItemKind::Mac(dummy_spanned(ast::Mac_ {
-                path: ast::Path { span: syntax_pos::DUMMY_SP, global: false, segments: Vec::new() },
-                tts: Vec::new(),
-            })),
-            vis: ast::Visibility::Inherited,
-            span: syntax_pos::DUMMY_SP,
-        })))
+pub fn expand_expr(expr: ast::Expr, fld: &mut MacroExpander) -> P<ast::Expr> {
+    if let ast::ExprKind::Mac(mac) = expr.node {
+        let invoc = fld.new_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::Expr);
+        expand_mac_invoc(invoc, fld).make_expr()
+    } else {
+        P(noop_fold_expr(expr, fld))
     }
 }
 
 /// Expand a macro invocation. Returns the result of expansion.
-fn expand_mac_invoc<T>(mac: ast::Mac, ident: Option<Ident>, attrs: Vec<ast::Attribute>, span: Span,
-                       fld: &mut MacroExpander) -> T
-    where T: MacroGenerable,
-{
-    // It would almost certainly be cleaner to pass the whole macro invocation in,
-    // rather than pulling it apart and marking the tts and the ctxt separately.
+fn expand_mac_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
+    let Invocation { span, attrs, mac, ident, mark, kind } = invoc;
     let Mac_ { path, tts, .. } = mac.node;
-    let mark = Mark::fresh();
-
-    fn mac_result<'a>(path: &ast::Path, ident: Option<Ident>, tts: Vec<TokenTree>, mark: Mark,
-                      attrs: Vec<ast::Attribute>, call_site: Span, fld: &'a mut MacroExpander)
-                      -> Option<Box<MacResult + 'a>> {
-        // Detect use of feature-gated or invalid attributes on macro invoations
-        // since they will not be detected after macro expansion.
-        for attr in attrs.iter() {
-            feature_gate::check_attribute(&attr, &fld.cx.parse_sess.span_diagnostic,
-                                          &fld.cx.parse_sess.codemap(),
-                                          &fld.cx.ecfg.features.unwrap());
-        }
-
-        if path.segments.len() > 1 || path.global || !path.segments[0].parameters.is_empty() {
-            fld.cx.span_err(path.span, "expected macro name without module separators");
-            return None;
-        }
 
-        let extname = path.segments[0].identifier.name;
-        let extension = if let Some(extension) = fld.cx.syntax_env.find(extname) {
-            extension
-        } else {
-            let mut err = fld.cx.struct_span_err(path.span,
-                                                 &format!("macro undefined: '{}!'", &extname));
-            fld.cx.suggest_macro_name(&extname.as_str(), &mut err);
-            err.emit();
-            return None;
-        };
+    // Detect use of feature-gated or invalid attributes on macro invoations
+    // since they will not be detected after macro expansion.
+    for attr in attrs.iter() {
+        feature_gate::check_attribute(&attr, &fld.cx.parse_sess.span_diagnostic,
+                                      &fld.cx.parse_sess.codemap(),
+                                      &fld.cx.ecfg.features.unwrap());
+    }
 
-        let ident = ident.unwrap_or(keywords::Invalid.ident());
-        let marked_tts = mark_tts(&tts, mark);
-        match *extension {
-            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);
-                    fld.cx.span_err(path.span, &msg);
-                    return None;
-                }
+    if path.segments.len() > 1 || path.global || !path.segments[0].parameters.is_empty() {
+        fld.cx.span_err(path.span, "expected macro name without module separators");
+        return kind.dummy(span);
+    }
 
-                fld.cx.bt_push(ExpnInfo {
-                    call_site: call_site,
-                    callee: NameAndSpan {
-                        format: MacroBang(extname),
-                        span: exp_span,
-                        allow_internal_unstable: allow_internal_unstable,
-                    },
-                });
+    let extname = path.segments[0].identifier.name;
+    let extension = if let Some(extension) = fld.cx.syntax_env.find(extname) {
+        extension
+    } else {
+        let mut err =
+            fld.cx.struct_span_err(path.span, &format!("macro undefined: '{}!'", &extname));
+        fld.cx.suggest_macro_name(&extname.as_str(), &mut err);
+        err.emit();
+        return kind.dummy(span);
+    };
 
-                Some(expandfun.expand(fld.cx, call_site, &marked_tts))
+    let ident = ident.unwrap_or(keywords::Invalid.ident());
+    let marked_tts = mark_tts(&tts, mark);
+    let opt_expanded = match *extension {
+        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);
+                fld.cx.span_err(path.span, &msg);
+                return kind.dummy(span);
             }
 
-            IdentTT(ref expander, tt_span, allow_internal_unstable) => {
-                if ident.name == keywords::Invalid.name() {
-                    fld.cx.span_err(path.span,
-                                    &format!("macro {}! expects an ident argument", extname));
-                    return None;
-                };
+            fld.cx.bt_push(ExpnInfo {
+                call_site: span,
+                callee: NameAndSpan {
+                    format: MacroBang(extname),
+                    span: exp_span,
+                    allow_internal_unstable: allow_internal_unstable,
+                },
+            });
 
-                fld.cx.bt_push(ExpnInfo {
-                    call_site: call_site,
-                    callee: NameAndSpan {
-                        format: MacroBang(extname),
-                        span: tt_span,
-                        allow_internal_unstable: allow_internal_unstable,
-                    }
-                });
+            kind.make_from(expandfun.expand(fld.cx, span, &marked_tts))
+        }
 
-                Some(expander.expand(fld.cx, call_site, ident, marked_tts))
-            }
+        IdentTT(ref expander, tt_span, allow_internal_unstable) => {
+            if ident.name == keywords::Invalid.name() {
+                fld.cx.span_err(path.span,
+                                &format!("macro {}! expects an ident argument", extname));
+                return kind.dummy(span);
+            };
 
-            MacroRulesTT => {
-                if ident.name == keywords::Invalid.name() {
-                    fld.cx.span_err(path.span,
-                                    &format!("macro {}! expects an ident argument", extname));
-                    return None;
-                };
+            fld.cx.bt_push(ExpnInfo {
+                call_site: span,
+                callee: NameAndSpan {
+                    format: MacroBang(extname),
+                    span: tt_span,
+                    allow_internal_unstable: allow_internal_unstable,
+                }
+            });
 
-                fld.cx.bt_push(ExpnInfo {
-                    call_site: call_site,
-                    callee: NameAndSpan {
-                        format: MacroBang(extname),
-                        span: None,
-                        // `macro_rules!` doesn't directly allow unstable
-                        // (this is orthogonal to whether the macro it creates allows it)
-                        allow_internal_unstable: false,
-                    }
-                });
+            kind.make_from(expander.expand(fld.cx, span, ident, marked_tts))
+        }
 
-                let def = ast::MacroDef {
-                    ident: ident,
-                    id: ast::DUMMY_NODE_ID,
-                    span: call_site,
-                    imported_from: None,
-                    use_locally: true,
-                    body: marked_tts,
-                    export: attr::contains_name(&attrs, "macro_export"),
-                    allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"),
-                    attrs: attrs,
-                };
+        MacroRulesTT => {
+            if ident.name == keywords::Invalid.name() {
+                fld.cx.span_err(path.span,
+                                &format!("macro {}! expects an ident argument", extname));
+                return kind.dummy(span);
+            };
 
-                fld.cx.insert_macro(def.clone());
-
-                // macro_rules! has a side effect, but expands to nothing.
-                // If keep_macs is true, expands to a MacEager::items instead.
-                if fld.keep_macs {
-                    Some(MacEager::items(SmallVector::one(P(ast::Item {
-                        ident: def.ident,
-                        attrs: def.attrs.clone(),
-                        id: ast::DUMMY_NODE_ID,
-                        node: ast::ItemKind::Mac(ast::Mac {
-                            span: def.span,
-                            node: ast::Mac_ {
-                                path: path.clone(),
-                                tts: def.body.clone(),
-                            }
-                        }),
-                        vis: ast::Visibility::Inherited,
-                        span: def.span,
-                    }))))
-                } else {
-                    Some(Box::new(MacroScopePlaceholder))
+            fld.cx.bt_push(ExpnInfo {
+                call_site: span,
+                callee: NameAndSpan {
+                    format: MacroBang(extname),
+                    span: None,
+                    // `macro_rules!` doesn't directly allow unstable
+                    // (this is orthogonal to whether the macro it creates allows it)
+                    allow_internal_unstable: false,
                 }
-            }
+            });
 
-            MultiDecorator(..) | MultiModifier(..) => {
-                fld.cx.span_err(path.span,
-                                &format!("`{}` can only be used in attributes", extname));
-                None
+            let def = ast::MacroDef {
+                ident: ident,
+                id: ast::DUMMY_NODE_ID,
+                span: span,
+                imported_from: None,
+                use_locally: true,
+                body: marked_tts,
+                export: attr::contains_name(&attrs, "macro_export"),
+                allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"),
+                attrs: attrs,
+            };
+
+            fld.cx.insert_macro(def.clone());
+
+            // If keep_macs is true, expands to a MacEager::items instead.
+            if fld.keep_macs {
+                Some(reconstruct_macro_rules(&def, &path))
+            } else {
+                Some(macro_scope_placeholder())
             }
         }
-    }
 
-    let opt_expanded = T::make_with(match mac_result(&path, ident, tts, mark, attrs, span, fld) {
-        Some(result) => result,
-        None => return T::dummy(span),
-    });
+        MultiDecorator(..) | MultiModifier(..) => {
+            fld.cx.span_err(path.span,
+                            &format!("`{}` can only be used in attributes", extname));
+            return kind.dummy(span);
+        }
+    };
 
     let expanded = if let Some(expanded) = opt_expanded {
         expanded
     } else {
         let msg = format!("non-{kind} macro in {kind} position: {name}",
-                          name = path.segments[0].identifier.name, kind = T::kind_name());
+                          name = path.segments[0].identifier.name, kind = kind.name());
         fld.cx.span_err(path.span, &msg);
-        return T::dummy(span);
+        return kind.dummy(span);
     };
 
     let marked = expanded.fold_with(&mut Marker { mark: mark, expn_id: Some(fld.cx.backtrace()) });
@@ -342,8 +323,8 @@ fn expand_stmt(stmt: Stmt, fld: &mut MacroExpander) -> SmallVector<Stmt> {
         _ => return noop_fold_stmt(stmt, fld)
     };
 
-    let mut fully_expanded: SmallVector<ast::Stmt> =
-        expand_mac_invoc(mac, None, attrs.into(), stmt.span, fld);
+    let invoc = fld.new_invoc(mac, attrs.into(), stmt.span, ExpansionKind::Stmts);
+    let mut fully_expanded = expand_mac_invoc(invoc, fld).make_stmts();
 
     // If this is a macro invocation with a semicolon, then apply that
     // semicolon to the final statement produced by expansion.
@@ -361,11 +342,12 @@ fn expand_pat(p: P<ast::Pat>, fld: &mut MacroExpander) -> P<ast::Pat> {
         PatKind::Mac(_) => {}
         _ => return noop_fold_pat(p, fld)
     }
-    p.and_then(|ast::Pat {node, span, ..}| {
-        match node {
-            PatKind::Mac(mac) => expand_mac_invoc(mac, None, Vec::new(), span, fld),
-            _ => unreachable!()
+    p.and_then(|p| match p.node {
+        PatKind::Mac(mac) => {
+            let invoc = fld.new_invoc(mac, Vec::new(), p.span, ExpansionKind::Pat);
+            expand_mac_invoc(invoc, fld).make_pat()
         }
+        _ => unreachable!(),
     })
 }
 
@@ -380,8 +362,11 @@ fn expand_multi_modified(a: Annotatable, fld: &mut MacroExpander) -> SmallVector
                     return SmallVector::one(Annotatable::Item(it));
                 }
                 it.and_then(|it| match it.node {
-                    ItemKind::Mac(mac) =>
-                        expand_mac_invoc(mac, Some(it.ident), it.attrs, it.span, fld),
+                    ItemKind::Mac(mac) => {
+                        let mut invoc = fld.new_invoc(mac, it.attrs, it.span, ExpansionKind::Items);
+                        invoc.ident = Some(it.ident);
+                        expand_mac_invoc(invoc, fld).make_items()
+                    }
                     _ => unreachable!(),
                 })
             }
@@ -472,7 +457,8 @@ fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander)
                  -> SmallVector<ast::ImplItem> {
     match ii.node {
         ast::ImplItemKind::Macro(mac) => {
-            expand_mac_invoc(mac, None, ii.attrs, ii.span, fld)
+            let invoc = fld.new_invoc(mac, ii.attrs, ii.span, ExpansionKind::ImplItems);
+            expand_mac_invoc(invoc, fld).make_impl_items()
         }
         _ => fold::noop_fold_impl_item(ii, fld)
     }
@@ -482,7 +468,8 @@ fn expand_trait_item(ti: ast::TraitItem, fld: &mut MacroExpander)
                      -> SmallVector<ast::TraitItem> {
     match ti.node {
         ast::TraitItemKind::Macro(mac) => {
-            expand_mac_invoc(mac, None, ti.attrs, ti.span, fld)
+            let invoc = fld.new_invoc(mac, ti.attrs, ti.span, ExpansionKind::TraitItems);
+            expand_mac_invoc(invoc, fld).make_trait_items()
         }
         _ => fold::noop_fold_trait_item(ti, fld)
     }
@@ -496,7 +483,8 @@ pub fn expand_type(t: P<ast::Ty>, fld: &mut MacroExpander) -> P<ast::Ty> {
 
     match t.node {
         ast::TyKind::Mac(mac) => {
-            expand_mac_invoc(mac, None, Vec::new(), t.span, fld)
+            let invoc = fld.new_invoc(mac, Vec::new(), t.span, ExpansionKind::Ty);
+            expand_mac_invoc(invoc, fld).make_ty()
         }
         _ => unreachable!(),
     }
@@ -529,7 +517,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         }
     }
 
-    fn load_macros<T: MacroGenerable>(&mut self, node: &T) {
+    fn load_macros(&mut self, node: &Expansion) {
         struct MacroLoadingVisitor<'a, 'b: 'a>{
             cx: &'a mut ExtCtxt<'b>,
             at_crate_root: bool,
@@ -567,6 +555,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             cx: self.cx,
         });
     }
+
+    fn new_invoc(&self, mac: ast::Mac, attrs: Vec<ast::Attribute>, span: Span, kind: ExpansionKind)
+                 -> Invocation {
+        let mark = Mark::fresh();
+        Invocation { span: span, attrs: attrs, mac: mac, mark: mark, kind: kind, ident: None }
+    }
 }
 
 impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
@@ -583,8 +577,11 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
 
     fn fold_opt_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
         expr.and_then(|expr| match expr.node {
-            ast::ExprKind::Mac(mac) =>
-                expand_mac_invoc(mac, None, expr.attrs.into(), expr.span, self),
+            ast::ExprKind::Mac(mac) => {
+                let invoc =
+                    self.new_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::OptExpr);
+                expand_mac_invoc(invoc, self).make_opt_expr()
+            }
             _ => Some(expand_expr(expr, self)),
         })
     }
@@ -647,6 +644,37 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
     }
 }
 
+fn macro_scope_placeholder() -> Expansion {
+    Expansion::Items(SmallVector::one(P(ast::Item {
+        ident: keywords::Invalid.ident(),
+        attrs: Vec::new(),
+        id: ast::DUMMY_NODE_ID,
+        node: ast::ItemKind::Mac(dummy_spanned(ast::Mac_ {
+            path: ast::Path { span: syntax_pos::DUMMY_SP, global: false, segments: Vec::new() },
+            tts: Vec::new(),
+        })),
+        vis: ast::Visibility::Inherited,
+        span: syntax_pos::DUMMY_SP,
+    })))
+}
+
+fn reconstruct_macro_rules(def: &ast::MacroDef, path: &ast::Path) -> Expansion {
+    Expansion::Items(SmallVector::one(P(ast::Item {
+        ident: def.ident,
+        attrs: def.attrs.clone(),
+        id: ast::DUMMY_NODE_ID,
+        node: ast::ItemKind::Mac(ast::Mac {
+            span: def.span,
+            node: ast::Mac_ {
+                path: path.clone(),
+                tts: def.body.clone(),
+            }
+        }),
+        vis: ast::Visibility::Inherited,
+        span: def.span,
+    })))
+}
+
 pub struct ExpansionConfig<'feat> {
     pub crate_name: String,
     pub features: Option<&'feat Features>,
@@ -718,10 +746,10 @@ pub fn expand_crate_with_expander(expander: &mut MacroExpander,
         expander.cx.syntax_env.insert(name, extension);
     }
 
-    let items = SmallVector::many(c.module.items);
+    let items = Expansion::Items(SmallVector::many(c.module.items));
     let configured = items.fold_with(&mut expander.strip_unconfigured());
     expander.load_macros(&configured);
-    c.module.items = configured.into();
+    c.module.items = configured.make_items().into();
 
     let err_count = expander.cx.parse_sess.span_diagnostic.err_count();
     let mut ret = expander.fold_crate(c);