about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2019-06-16 18:58:39 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2019-06-18 10:48:56 +0300
commit961ba8f9efbb51d80e7e73a609f6587c0ffa0623 (patch)
tree3864832e7a6bbf638639d0d0233f6c816548ec66
parent704ab2ba10c4d878f879047cdac94a61751ce943 (diff)
downloadrust-961ba8f9efbb51d80e7e73a609f6587c0ffa0623.tar.gz
rust-961ba8f9efbb51d80e7e73a609f6587c0ffa0623.zip
syntax: Factor out common fields from `SyntaxExtension` variants
-rw-r--r--src/doc/unstable-book/src/language-features/plugin.md2
-rw-r--r--src/librustc_allocator/expand.rs2
-rw-r--r--src/librustc_metadata/creader.rs50
-rw-r--r--src/librustc_metadata/cstore_impl.rs13
-rw-r--r--src/librustc_metadata/decoder.rs7
-rw-r--r--src/librustc_plugin/registry.rs22
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs11
-rw-r--r--src/librustc_resolve/macros.rs32
-rw-r--r--src/librustdoc/clean/inline.rs12
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs4
-rw-r--r--src/libsyntax/ext/base.rs148
-rw-r--r--src/libsyntax/ext/derive.rs2
-rw-r--r--src/libsyntax/ext/expand.rs178
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs12
-rw-r--r--src/libsyntax/std_inject.rs2
-rw-r--r--src/libsyntax/test.rs2
-rw-r--r--src/libsyntax_ext/deriving/mod.rs21
-rw-r--r--src/libsyntax_ext/lib.rs69
-rw-r--r--src/libsyntax_ext/proc_macro_decls.rs7
-rw-r--r--src/libsyntax_ext/test.rs2
-rw-r--r--src/libsyntax_ext/test_case.rs2
-rw-r--r--src/test/run-pass-fulldeps/auxiliary/plugin-args.rs18
22 files changed, 269 insertions, 349 deletions
diff --git a/src/doc/unstable-book/src/language-features/plugin.md b/src/doc/unstable-book/src/language-features/plugin.md
index 1994cf49188..0e38e2865d8 100644
--- a/src/doc/unstable-book/src/language-features/plugin.md
+++ b/src/doc/unstable-book/src/language-features/plugin.md
@@ -132,7 +132,7 @@ The advantages over a simple `fn(&str) -> u32` are:
 In addition to procedural macros, you can define new
 [`derive`](../../reference/attributes/derive.md)-like attributes and other kinds
 of extensions.  See `Registry::register_syntax_extension` and the
-`SyntaxExtension` enum.  For a more involved macro example, see
+`SyntaxExtension` struct.  For a more involved macro example, see
 [`regex_macros`](https://github.com/rust-lang/regex/blob/master/regex_macros/src/lib.rs).
 
 
diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs
index 3ec06b17aff..ecc165ca5ea 100644
--- a/src/librustc_allocator/expand.rs
+++ b/src/librustc_allocator/expand.rs
@@ -91,7 +91,7 @@ impl MutVisitor for ExpandAllocatorDirectives<'_> {
             call_site: item.span, // use the call site of the static
             def_site: None,
             format: MacroAttribute(Symbol::intern(name)),
-            allow_internal_unstable: Some(vec![sym::rustc_attrs].into()),
+            allow_internal_unstable: Some([sym::rustc_attrs][..].into()),
             allow_internal_unsafe: false,
             local_inner_macros: false,
             edition: self.sess.edition,
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 5fef8e53e1d..d3d00fa4adc 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -26,7 +26,7 @@ use std::{cmp, fs};
 
 use syntax::ast;
 use syntax::attr;
-use syntax::ext::base::SyntaxExtension;
+use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind};
 use syntax::symbol::{Symbol, sym};
 use syntax::visit;
 use syntax::{span_err, span_fatal};
@@ -611,33 +611,31 @@ impl<'a> CrateLoader<'a> {
         };
 
         let extensions = decls.iter().map(|&decl| {
-            match decl {
+            let (name, kind, helper_attrs) = match decl {
                 ProcMacro::CustomDerive { trait_name, attributes, client } => {
-                    let attrs = attributes.iter().cloned().map(Symbol::intern).collect::<Vec<_>>();
-                    (trait_name, SyntaxExtension::Derive(
-                        Box::new(ProcMacroDerive {
-                            client,
-                            attrs: attrs.clone(),
-                        }),
-                        attrs,
-                        root.edition,
-                    ))
+                    let helper_attrs =
+                        attributes.iter().cloned().map(Symbol::intern).collect::<Vec<_>>();
+                    (
+                        trait_name,
+                        SyntaxExtensionKind::Derive(Box::new(ProcMacroDerive {
+                            client, attrs: helper_attrs.clone()
+                        })),
+                        helper_attrs,
+                    )
                 }
-                ProcMacro::Attr { name, client } => {
-                    (name, SyntaxExtension::Attr(
-                        Box::new(AttrProcMacro { client }),
-                        root.edition,
-                    ))
-                }
-                ProcMacro::Bang { name, client } => {
-                    (name, SyntaxExtension::Bang {
-                        expander: Box::new(BangProcMacro { client }),
-                        allow_internal_unstable: None,
-                        edition: root.edition,
-                    })
-                }
-            }
-        }).map(|(name, ext)| (Symbol::intern(name), Lrc::new(ext))).collect();
+                ProcMacro::Attr { name, client } => (
+                    name, SyntaxExtensionKind::Attr(Box::new(AttrProcMacro { client })), Vec::new()
+                ),
+                ProcMacro::Bang { name, client } => (
+                    name, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })), Vec::new()
+                )
+            };
+
+            (Symbol::intern(name), Lrc::new(SyntaxExtension {
+                helper_attrs,
+                ..SyntaxExtension::default(kind, root.edition)
+            }))
+        }).collect();
 
         // Intentionally leak the dynamic library. We can't ever unload it
         // since the library can make things that will live arbitrarily long.
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 86536b179f2..04a9c4e9a1a 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -30,9 +30,11 @@ use syntax::ast;
 use syntax::attr;
 use syntax::source_map;
 use syntax::edition::Edition;
+use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind};
 use syntax::parse::source_file_to_stream;
 use syntax::parse::parser::emit_unclosed_delims;
 use syntax::symbol::{Symbol, sym};
+use syntax_ext::proc_macro_impl::BangProcMacro;
 use syntax_pos::{Span, NO_EXPANSION, FileName};
 use rustc_data_structures::bit_set::BitSet;
 
@@ -427,14 +429,11 @@ impl cstore::CStore {
         if let Some(ref proc_macros) = data.proc_macros {
             return LoadedMacro::ProcMacro(proc_macros[id.index.to_proc_macro_index()].1.clone());
         } else if data.name == sym::proc_macro && data.item_name(id.index) == sym::quote {
-            use syntax::ext::base::SyntaxExtension;
-            use syntax_ext::proc_macro_impl::BangProcMacro;
-
             let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote);
-            let ext = SyntaxExtension::Bang {
-                expander: Box::new(BangProcMacro { client }),
-                allow_internal_unstable: Some(vec![sym::proc_macro_def_site].into()),
-                edition: data.root.edition,
+            let kind = SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client }));
+            let ext = SyntaxExtension {
+                allow_internal_unstable: Some([sym::proc_macro_def_site][..].into()),
+                ..SyntaxExtension::default(kind, data.root.edition)
             };
             return LoadedMacro::ProcMacro(Lrc::new(ext));
         }
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 4bafe16b8e6..a776966bda4 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -511,8 +511,9 @@ impl<'a, 'tcx> CrateMetadata {
         if !self.is_proc_macro(index) {
             self.entry(index).kind.def_kind()
         } else {
-            let kind = self.proc_macros.as_ref().unwrap()[index.to_proc_macro_index()].1.kind();
-            Some(DefKind::Macro(kind))
+            Some(DefKind::Macro(
+                self.proc_macros.as_ref().unwrap()[index.to_proc_macro_index()].1.macro_kind()
+            ))
         }
     }
 
@@ -739,7 +740,7 @@ impl<'a, 'tcx> CrateMetadata {
             if id == CRATE_DEF_INDEX {
                 for (id, &(name, ref ext)) in proc_macros.iter().enumerate() {
                     let res = Res::Def(
-                        DefKind::Macro(ext.kind()),
+                        DefKind::Macro(ext.macro_kind()),
                         self.local_def_id(DefIndex::from_proc_macro_index(id)),
                     );
                     let ident = Ident::with_empty_ctxt(name);
diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs
index dd5e42684c4..16d484e2a98 100644
--- a/src/librustc_plugin/registry.rs
+++ b/src/librustc_plugin/registry.rs
@@ -4,9 +4,8 @@ use rustc::lint::{EarlyLintPassObject, LateLintPassObject, LintId, Lint};
 use rustc::session::Session;
 use rustc::util::nodemap::FxHashMap;
 
-use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension};
+use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind, NamedSyntaxExtension};
 use syntax::ext::base::MacroExpanderFn;
-use syntax::ext::hygiene::Transparency;
 use syntax::symbol::{Symbol, sym};
 use syntax::ast;
 use syntax::feature_gate::AttributeType;
@@ -89,8 +88,8 @@ impl<'a> Registry<'a> {
         if name == sym::macro_rules {
             panic!("user-defined macros may not be named `macro_rules`");
         }
-        if let SyntaxExtension::LegacyBang { def_info: ref mut def_info @ None, .. } = extension {
-            *def_info = Some((ast::CRATE_NODE_ID, self.krate_span));
+        if extension.def_info.is_none() {
+            extension.def_info = Some((ast::CRATE_NODE_ID, self.krate_span));
         }
         self.syntax_exts.push((name, extension));
     }
@@ -98,19 +97,12 @@ impl<'a> Registry<'a> {
     /// Register a macro of the usual kind.
     ///
     /// This is a convenience wrapper for `register_syntax_extension`.
-    /// It builds for you a `SyntaxExtension::LegacyBang` that calls `expander`,
+    /// It builds for you a `SyntaxExtensionKind::LegacyBang` that calls `expander`,
     /// and also takes care of interning the macro's name.
     pub fn register_macro(&mut self, name: &str, expander: MacroExpanderFn) {
-        self.register_syntax_extension(Symbol::intern(name), SyntaxExtension::LegacyBang {
-            expander: Box::new(expander),
-            def_info: None,
-            transparency: Transparency::SemiTransparent,
-            allow_internal_unstable: None,
-            allow_internal_unsafe: false,
-            local_inner_macros: false,
-            unstable_feature: None,
-            edition: self.sess.edition(),
-        });
+        let kind = SyntaxExtensionKind::LegacyBang(Box::new(expander));
+        let ext = SyntaxExtension::default(kind, self.sess.edition());
+        self.register_syntax_extension(Symbol::intern(name), ext);
     }
 
     /// Register a compiler lint pass.
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index e3cd2948d7a..bb4edf355f8 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -29,7 +29,7 @@ use syntax::attr;
 
 use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind, NodeId};
 use syntax::ast::{MetaItemKind, StmtKind, TraitItem, TraitItemKind, Variant};
-use syntax::ext::base::{MacroKind, SyntaxExtension};
+use syntax::ext::base::{MacroKind, SyntaxExtension, SyntaxExtensionKind};
 use syntax::ext::base::Determinacy::Undetermined;
 use syntax::ext::hygiene::Mark;
 use syntax::ext::tt::macro_rules;
@@ -772,9 +772,12 @@ impl<'a> Resolver<'a> {
     pub fn get_macro(&mut self, res: Res) -> Lrc<SyntaxExtension> {
         let def_id = match res {
             Res::Def(DefKind::Macro(..), def_id) => def_id,
-            Res::NonMacroAttr(attr_kind) => return Lrc::new(SyntaxExtension::NonMacroAttr {
-                mark_used: attr_kind == NonMacroAttrKind::Tool,
-            }),
+            Res::NonMacroAttr(attr_kind) => return Lrc::new(SyntaxExtension::default(
+                SyntaxExtensionKind::NonMacroAttr {
+                    mark_used: attr_kind == NonMacroAttrKind::Tool
+                },
+                self.session.edition(),
+            )),
             _ => panic!("expected `DefKind::Macro` or `Res::NonMacroAttr`"),
         };
         if let Some(ext) = self.macro_map.get(&def_id) {
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 2369bddf4f7..89e28330be7 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -15,7 +15,7 @@ use syntax::ast::{self, Ident};
 use syntax::attr;
 use syntax::errors::DiagnosticBuilder;
 use syntax::ext::base::{self, Determinacy};
-use syntax::ext::base::{MacroKind, SyntaxExtension};
+use syntax::ext::base::{MacroKind, SyntaxExtension, SyntaxExtensionKind};
 use syntax::ext::expand::{AstFragment, Invocation, InvocationKind};
 use syntax::ext::hygiene::Mark;
 use syntax::ext::tt::macro_rules;
@@ -174,7 +174,7 @@ impl<'a> base::Resolver for Resolver<'a> {
             krate: CrateNum::BuiltinMacros,
             index: DefIndex::from(self.macro_map.len()),
         };
-        let kind = ext.kind();
+        let kind = ext.macro_kind();
         self.macro_map.insert(def_id, ext);
         let binding = self.arenas.alloc_name_binding(NameBinding {
             kind: NameBindingKind::Res(Res::Def(DefKind::Macro(kind), def_id), false),
@@ -211,7 +211,8 @@ impl<'a> base::Resolver for Resolver<'a> {
             Ok((res, ext)) => (res, ext),
             Err(Determinacy::Determined) if kind == MacroKind::Attr => {
                 // Replace unresolved attributes with used inert attributes for better recovery.
-                return Ok(Some(Lrc::new(SyntaxExtension::NonMacroAttr { mark_used: true })));
+                let kind = SyntaxExtensionKind::NonMacroAttr { mark_used: true };
+                return Ok(Some(Lrc::new(SyntaxExtension::default(kind, self.session.edition()))));
             }
             Err(determinacy) => return Err(determinacy),
         };
@@ -226,7 +227,7 @@ impl<'a> base::Resolver for Resolver<'a> {
                 self.macro_def_scope(invoc.expansion_data.mark).normal_ancestor_id;
             self.definitions.add_parent_module_of_macro_def(invoc.expansion_data.mark,
                                                             normal_module_def_id);
-            invoc.expansion_data.mark.set_default_transparency(ext.default_transparency());
+            invoc.expansion_data.mark.set_default_transparency(ext.default_transparency);
         }
 
         Ok(Some(ext))
@@ -241,11 +242,7 @@ impl<'a> base::Resolver for Resolver<'a> {
 
     fn check_unused_macros(&self) {
         for did in self.unused_macros.iter() {
-            let id_span = match *self.macro_map[did] {
-                SyntaxExtension::LegacyBang { def_info, .. } => def_info,
-                _ => None,
-            };
-            if let Some((id, span)) = id_span {
+            if let Some((id, span)) = self.macro_map[did].def_info {
                 let lint = lint::builtin::UNUSED_MACROS;
                 let msg = "unused macro definition";
                 self.session.buffer_lint(lint, id, span, msg);
@@ -585,17 +582,12 @@ impl<'a> Resolver<'a> {
                         let parent_scope = ParentScope { derives: Vec::new(), ..*parent_scope };
                         match self.resolve_macro_to_res(derive, MacroKind::Derive,
                                                         &parent_scope, true, force) {
-                            Ok((_, ext)) => {
-                                if let SyntaxExtension::Derive(_, helpers, _) = &*ext {
-                                    if helpers.contains(&ident.name) {
-                                        let binding =
-                                            (Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
-                                            ty::Visibility::Public, derive.span, Mark::root())
-                                            .to_name_binding(self.arenas);
-                                        result = Ok((binding, Flags::empty()));
-                                        break;
-                                    }
-                                }
+                            Ok((_, ext)) => if ext.helper_attrs.contains(&ident.name) {
+                                let binding = (Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
+                                               ty::Visibility::Public, derive.span, Mark::root())
+                                               .to_name_binding(self.arenas);
+                                result = Ok((binding, Flags::empty()));
+                                break;
                             }
                             Err(Determinacy::Determined) => {}
                             Err(Determinacy::Undetermined) =>
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index c14ae5932af..9259b3b5d3a 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -3,7 +3,7 @@
 use std::iter::once;
 
 use syntax::ast;
-use syntax::ext::base::{MacroKind, SyntaxExtension};
+use syntax::ext::base::MacroKind;
 use syntax::symbol::sym;
 use syntax_pos::Span;
 
@@ -470,18 +470,12 @@ fn build_macro(cx: &DocContext<'_>, did: DefId, name: ast::Name) -> clean::ItemE
             })
         }
         LoadedMacro::ProcMacro(ext) => {
-            let helpers = match &*ext {
-                &SyntaxExtension::Derive(_, ref syms, ..) => { syms.clean(cx) }
-                _ => Vec::new(),
-            };
-
             clean::ProcMacroItem(clean::ProcMacro {
-                kind: ext.kind(),
-                helpers,
+                kind: ext.macro_kind(),
+                helpers: ext.helper_attrs.clean(cx),
             })
         }
     }
-
 }
 
 /// A trait's generics clause actually contains all of the predicates for all of
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 7fbfc3e1fc0..68b96a40829 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -423,7 +423,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
 
 /// Resolves a string as a macro.
 fn macro_resolve(cx: &DocContext<'_>, path_str: &str) -> Option<Res> {
-    use syntax::ext::base::{MacroKind, SyntaxExtension};
+    use syntax::ext::base::{MacroKind, SyntaxExtensionKind};
     let segment = ast::PathSegment::from_ident(Ident::from_str(path_str));
     let path = ast::Path { segments: vec![segment], span: DUMMY_SP };
     cx.enter_resolver(|resolver| {
@@ -433,7 +433,7 @@ fn macro_resolve(cx: &DocContext<'_>, path_str: &str) -> Option<Res> {
             if let Res::Def(DefKind::Macro(MacroKind::ProcMacroStub), _) = res {
                 // skip proc-macro stubs, they'll cause `get_macro` to crash
             } else {
-                if let SyntaxExtension::LegacyBang { .. } = *resolver.get_macro(res) {
+                if let SyntaxExtensionKind::LegacyBang(..) = resolver.get_macro(res).kind {
                     return Some(res.map_id(|_| panic!("unexpected id")));
                 }
             }
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 38b7dee40c4..04cef0bba24 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -15,6 +15,7 @@ use crate::tokenstream::{self, TokenStream};
 use errors::{DiagnosticBuilder, DiagnosticId};
 use smallvec::{smallvec, SmallVec};
 use syntax_pos::{Span, MultiSpan, DUMMY_SP};
+use syntax_pos::hygiene::{ExpnInfo, ExpnFormat};
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::{self, Lrc};
@@ -548,37 +549,19 @@ impl MacroKind {
     }
 }
 
-/// An enum representing the different kinds of syntax extensions.
-pub enum SyntaxExtension {
+/// A syntax extension kind.
+pub enum SyntaxExtensionKind {
     /// A token-based function-like macro.
-    Bang {
+    Bang(
         /// An expander with signature TokenStream -> TokenStream.
-        expander: Box<dyn ProcMacro + sync::Sync + sync::Send>,
-        /// Whitelist of unstable features that are treated as stable inside this macro.
-        allow_internal_unstable: Option<Lrc<[Symbol]>>,
-        /// Edition of the crate in which this macro is defined.
-        edition: Edition,
-    },
+        Box<dyn ProcMacro + sync::Sync + sync::Send>,
+    ),
 
     /// An AST-based function-like macro.
-    LegacyBang {
+    LegacyBang(
         /// An expander with signature TokenStream -> AST.
-        expander: Box<dyn TTMacroExpander + sync::Sync + sync::Send>,
-        /// Some info about the macro's definition point.
-        def_info: Option<(ast::NodeId, Span)>,
-        /// Hygienic properties of identifiers produced by this macro.
-        transparency: Transparency,
-        /// Whitelist of unstable features that are treated as stable inside this macro.
-        allow_internal_unstable: Option<Lrc<[Symbol]>>,
-        /// Suppresses the `unsafe_code` lint for code produced by this macro.
-        allow_internal_unsafe: bool,
-        /// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro.
-        local_inner_macros: bool,
-        /// The macro's feature name and tracking issue number if it is unstable.
-        unstable_feature: Option<(Symbol, u32)>,
-        /// Edition of the crate in which this macro is defined.
-        edition: Edition,
-    },
+        Box<dyn TTMacroExpander + sync::Sync + sync::Send>,
+    ),
 
     /// A token-based attribute macro.
     Attr(
@@ -586,8 +569,6 @@ pub enum SyntaxExtension {
         /// The first TokenSteam is the attribute itself, the second is the annotated item.
         /// The produced TokenSteam replaces the input TokenSteam.
         Box<dyn AttrProcMacro + sync::Sync + sync::Send>,
-        /// Edition of the crate in which this macro is defined.
-        Edition,
     ),
 
     /// An AST-based attribute macro.
@@ -599,7 +580,8 @@ pub enum SyntaxExtension {
     ),
 
     /// A trivial attribute "macro" that does nothing,
-    /// only keeps the attribute and marks it as known.
+    /// only keeps the attribute and marks it as inert,
+    /// thus making it ineligible for further expansion.
     NonMacroAttr {
         /// Suppresses the `unused_attributes` lint for this attribute.
         mark_used: bool,
@@ -610,10 +592,6 @@ pub enum SyntaxExtension {
         /// An expander with signature TokenStream -> TokenStream (not yet).
         /// The produced TokenSteam is appended to the input TokenSteam.
         Box<dyn MultiItemModifier + sync::Sync + sync::Send>,
-        /// Names of helper attributes registered by this macro.
-        Vec<Symbol>,
-        /// Edition of the crate in which this macro is defined.
-        Edition,
     ),
 
     /// An AST-based derive macro.
@@ -624,42 +602,90 @@ pub enum SyntaxExtension {
     ),
 }
 
+/// A struct representing a macro definition in "lowered" form ready for expansion.
+pub struct SyntaxExtension {
+    /// A syntax extension kind.
+    pub kind: SyntaxExtensionKind,
+    /// Some info about the macro's definition point.
+    pub def_info: Option<(ast::NodeId, Span)>,
+    /// Hygienic properties of spans produced by this macro by default.
+    pub default_transparency: Transparency,
+    /// Whitelist of unstable features that are treated as stable inside this macro.
+    pub allow_internal_unstable: Option<Lrc<[Symbol]>>,
+    /// Suppresses the `unsafe_code` lint for code produced by this macro.
+    pub allow_internal_unsafe: bool,
+    /// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro.
+    pub local_inner_macros: bool,
+    /// The macro's feature name and tracking issue number if it is unstable.
+    pub unstable_feature: Option<(Symbol, u32)>,
+    /// Names of helper attributes registered by this macro.
+    pub helper_attrs: Vec<Symbol>,
+    /// Edition of the crate in which this macro is defined.
+    pub edition: Edition,
+}
+
+impl SyntaxExtensionKind {
+    /// When a syntax extension is constructed,
+    /// its transparency can often be inferred from its kind.
+    fn default_transparency(&self) -> Transparency {
+        match self {
+            SyntaxExtensionKind::Bang(..) |
+            SyntaxExtensionKind::Attr(..) |
+            SyntaxExtensionKind::Derive(..) |
+            SyntaxExtensionKind::NonMacroAttr { .. } => Transparency::Opaque,
+            SyntaxExtensionKind::LegacyBang(..) |
+            SyntaxExtensionKind::LegacyAttr(..) |
+            SyntaxExtensionKind::LegacyDerive(..) => Transparency::SemiTransparent,
+        }
+    }
+}
+
 impl SyntaxExtension {
     /// Returns which kind of macro calls this syntax extension.
-    pub fn kind(&self) -> MacroKind {
-        match *self {
-            SyntaxExtension::Bang { .. } |
-            SyntaxExtension::LegacyBang { .. } => MacroKind::Bang,
-            SyntaxExtension::Attr(..) |
-            SyntaxExtension::LegacyAttr(..) |
-            SyntaxExtension::NonMacroAttr { .. } => MacroKind::Attr,
-            SyntaxExtension::Derive(..) |
-            SyntaxExtension::LegacyDerive(..) => MacroKind::Derive,
+    pub fn macro_kind(&self) -> MacroKind {
+        match self.kind {
+            SyntaxExtensionKind::Bang(..) |
+            SyntaxExtensionKind::LegacyBang(..) => MacroKind::Bang,
+            SyntaxExtensionKind::Attr(..) |
+            SyntaxExtensionKind::LegacyAttr(..) |
+            SyntaxExtensionKind::NonMacroAttr { .. } => MacroKind::Attr,
+            SyntaxExtensionKind::Derive(..) |
+            SyntaxExtensionKind::LegacyDerive(..) => MacroKind::Derive,
         }
     }
 
-    pub fn default_transparency(&self) -> Transparency {
-        match *self {
-            SyntaxExtension::LegacyBang { transparency, .. } => transparency,
-            SyntaxExtension::Bang { .. } |
-            SyntaxExtension::Attr(..) |
-            SyntaxExtension::Derive(..) |
-            SyntaxExtension::NonMacroAttr { .. } => Transparency::Opaque,
-            SyntaxExtension::LegacyAttr(..) |
-            SyntaxExtension::LegacyDerive(..) => Transparency::SemiTransparent,
+    /// Constructs a syntax extension with default properties.
+    pub fn default(kind: SyntaxExtensionKind, edition: Edition) -> SyntaxExtension {
+        SyntaxExtension {
+            def_info: None,
+            default_transparency: kind.default_transparency(),
+            allow_internal_unstable: None,
+            allow_internal_unsafe: false,
+            local_inner_macros: false,
+            unstable_feature: None,
+            helper_attrs: Vec::new(),
+            edition,
+            kind,
         }
     }
 
-    pub fn edition(&self, default_edition: Edition) -> Edition {
-        match *self {
-            SyntaxExtension::Bang { edition, .. } |
-            SyntaxExtension::LegacyBang { edition, .. } |
-            SyntaxExtension::Attr(.., edition) |
-            SyntaxExtension::Derive(.., edition) => edition,
-            // Unstable legacy stuff
-            SyntaxExtension::NonMacroAttr { .. } |
-            SyntaxExtension::LegacyAttr(..) |
-            SyntaxExtension::LegacyDerive(..) => default_edition,
+    fn expn_format(&self, symbol: Symbol) -> ExpnFormat {
+        match self.kind {
+            SyntaxExtensionKind::Bang(..) |
+            SyntaxExtensionKind::LegacyBang(..) => ExpnFormat::MacroBang(symbol),
+            _ => ExpnFormat::MacroAttribute(symbol),
+        }
+    }
+
+    crate fn expn_info(&self, call_site: Span, format: &str) -> ExpnInfo {
+        ExpnInfo {
+            call_site,
+            def_site: self.def_info.map(|(_, span)| span),
+            format: self.expn_format(Symbol::intern(format)),
+            allow_internal_unstable: self.allow_internal_unstable.clone(),
+            allow_internal_unsafe: self.allow_internal_unsafe,
+            local_inner_macros: self.local_inner_macros,
+            edition: self.edition,
         }
     }
 }
diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs
index a2cf4a2a82d..33620cb80f9 100644
--- a/src/libsyntax/ext/derive.rs
+++ b/src/libsyntax/ext/derive.rs
@@ -64,7 +64,7 @@ pub fn add_derived_markers<T>(cx: &mut ExtCtxt<'_>, span: Span, traits: &[ast::P
         call_site: span,
         def_site: None,
         format: ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)),
-        allow_internal_unstable: Some(vec![sym::rustc_attrs, sym::structural_match].into()),
+        allow_internal_unstable: Some([sym::rustc_attrs, sym::structural_match][..].into()),
         allow_internal_unsafe: false,
         local_inner_macros: false,
         edition: cx.parse_sess.edition,
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 3fa96c60bff..4e759c5e528 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -1,7 +1,7 @@
 use crate::ast::{self, Block, Ident, LitKind, NodeId, PatKind, Path};
 use crate::ast::{MacStmtStyle, StmtKind, ItemKind};
 use crate::attr::{self, HasAttrs};
-use crate::source_map::{ExpnInfo, MacroBang, MacroAttribute, dummy_spanned, respan};
+use crate::source_map::{dummy_spanned, respan};
 use crate::config::StripUnconfigured;
 use crate::ext::base::*;
 use crate::ext::derive::{add_derived_markers, collect_derives};
@@ -22,7 +22,6 @@ use crate::util::map_in_place::MapInPlace;
 use errors::{Applicability, FatalError};
 use smallvec::{smallvec, SmallVec};
 use syntax_pos::{Span, DUMMY_SP, FileName};
-use syntax_pos::hygiene::ExpnFormat;
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lrc;
@@ -189,10 +188,10 @@ impl AstFragmentKind {
     }
 }
 
-fn macro_bang_format(path: &ast::Path) -> ExpnFormat {
-    // We don't want to format a path using pretty-printing,
-    // `format!("{}", path)`, because that tries to insert
-    // line-breaks and is slow.
+// We don't want to format a path using pretty-printing,
+// `format!("{}", path)`, because that tries to insert
+// line-breaks and is slow.
+fn fast_print_path(path: &ast::Path) -> String {
     let mut path_str = String::with_capacity(64);
     for (i, segment) in path.segments.iter().enumerate() {
         if i != 0 {
@@ -202,8 +201,7 @@ fn macro_bang_format(path: &ast::Path) -> ExpnFormat {
             path_str.push_str(&segment.ident.as_str())
         }
     }
-
-    MacroBang(Symbol::intern(&path_str))
+    path_str
 }
 
 pub struct Invocation {
@@ -388,8 +386,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                         derives.push(mark);
                         let item = match self.cx.resolver.resolve_macro_path(
                                 path, MacroKind::Derive, Mark::root(), Vec::new(), false) {
-                            Ok(ext) => match *ext {
-                                SyntaxExtension::LegacyDerive(..) => item_with_markers.clone(),
+                            Ok(ext) => match ext.kind {
+                                SyntaxExtensionKind::LegacyDerive(..) => item_with_markers.clone(),
                                 _ => item.clone(),
                             },
                             _ => item.clone(),
@@ -509,7 +507,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
     fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) -> Option<AstFragment> {
         if invoc.fragment_kind == AstFragmentKind::ForeignItems &&
            !self.cx.ecfg.macros_in_extern_enabled() {
-            if let SyntaxExtension::NonMacroAttr { .. } = *ext {} else {
+            if let SyntaxExtensionKind::NonMacroAttr { .. } = ext.kind {} else {
                 emit_feature_err(&self.cx.parse_sess, sym::macros_in_extern,
                                  invoc.span(), GateIssue::Language,
                                  "macro invocations in `extern {}` blocks are experimental");
@@ -548,34 +546,25 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             _ => unreachable!(),
         };
 
-        if let SyntaxExtension::NonMacroAttr { mark_used: false } = *ext {} else {
-            // Macro attrs are always used when expanded,
-            // non-macro attrs are considered used when the field says so.
-            attr::mark_used(&attr);
-        }
-        invoc.expansion_data.mark.set_expn_info(ExpnInfo {
-            call_site: attr.span,
-            def_site: None,
-            format: MacroAttribute(Symbol::intern(&attr.path.to_string())),
-            allow_internal_unstable: None,
-            allow_internal_unsafe: false,
-            local_inner_macros: false,
-            edition: ext.edition(self.cx.parse_sess.edition),
-        });
+        let expn_info = ext.expn_info(attr.span, &fast_print_path(&attr.path));
+        invoc.expansion_data.mark.set_expn_info(expn_info);
 
-        match *ext {
-            SyntaxExtension::NonMacroAttr { .. } => {
+        match &ext.kind {
+            SyntaxExtensionKind::NonMacroAttr { mark_used } => {
                 attr::mark_known(&attr);
+                if *mark_used {
+                    attr::mark_used(&attr);
+                }
                 item.visit_attrs(|attrs| attrs.push(attr));
                 Some(invoc.fragment_kind.expect_from_annotatables(iter::once(item)))
             }
-            SyntaxExtension::LegacyAttr(ref mac) => {
+            SyntaxExtensionKind::LegacyAttr(expander) => {
                 let meta = attr.parse_meta(self.cx.parse_sess)
                                .map_err(|mut e| { e.emit(); }).ok()?;
-                let item = mac.expand(self.cx, attr.span, &meta, item);
+                let item = expander.expand(self.cx, attr.span, &meta, item);
                 Some(invoc.fragment_kind.expect_from_annotatables(item))
             }
-            SyntaxExtension::Attr(ref mac, ..) => {
+            SyntaxExtensionKind::Attr(expander) => {
                 self.gate_proc_macro_attr_item(attr.span, &item);
                 let item_tok = TokenTree::token(token::Interpolated(Lrc::new(match item {
                     Annotatable::Item(item) => token::NtItem(item),
@@ -586,13 +575,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     Annotatable::Expr(expr) => token::NtExpr(expr),
                 })), DUMMY_SP).into();
                 let input = self.extract_proc_macro_attr_input(attr.tokens, attr.span);
-                let tok_result = mac.expand(self.cx, attr.span, input, item_tok);
+                let tok_result = expander.expand(self.cx, attr.span, input, item_tok);
                 let res = self.parse_ast_fragment(tok_result, invoc.fragment_kind,
                                                   &attr.path, attr.span);
                 self.gate_proc_macro_expansion(attr.span, &res);
                 res
             }
-            SyntaxExtension::Derive(..) | SyntaxExtension::LegacyDerive(..) => {
+            SyntaxExtensionKind::Derive(..) | SyntaxExtensionKind::LegacyDerive(..) => {
                 self.cx.span_err(attr.span, &format!("`{}` is a derive macro", attr.path));
                 self.cx.trace_macros_diag();
                 invoc.fragment_kind.dummy(attr.span)
@@ -701,21 +690,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         let path = &mac.node.path;
 
         let ident = ident.unwrap_or_else(|| Ident::invalid());
-        let validate_and_set_expn_info = |this: &mut Self, // arg instead of capture
-                                          def_site_span: Option<Span>,
-                                          allow_internal_unstable,
-                                          allow_internal_unsafe,
-                                          local_inner_macros,
-                                          // can't infer this type
-                                          unstable_feature: Option<(Symbol, u32)>,
-                                          edition| {
-
+        let validate_and_set_expn_info = |this: &mut Self| {
             // feature-gate the macro invocation
-            if let Some((feature, issue)) = unstable_feature {
+            if let Some((feature, issue)) = ext.unstable_feature {
                 let crate_span = this.cx.current_expansion.crate_span.unwrap();
                 // don't stability-check macros in the same crate
                 // (the only time this is null is for syntax extensions registered as macros)
-                if def_site_span.map_or(false, |def_span| !crate_span.contains(def_span))
+                if ext.def_info.map_or(false, |(_, def_span)| !crate_span.contains(def_span))
                     && !span.allows_unstable(feature)
                     && this.cx.ecfg.features.map_or(true, |feats| {
                     // macro features will count as lib features
@@ -734,62 +715,40 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 this.cx.trace_macros_diag();
                 return Err(kind.dummy(span));
             }
-            mark.set_expn_info(ExpnInfo {
-                call_site: span,
-                def_site: def_site_span,
-                format: macro_bang_format(path),
-                allow_internal_unstable,
-                allow_internal_unsafe,
-                local_inner_macros,
-                edition,
-            });
+            mark.set_expn_info(ext.expn_info(span, &fast_print_path(path)));
             Ok(())
         };
 
-        let opt_expanded = match *ext {
-            SyntaxExtension::LegacyBang {
-                ref expander,
-                def_info,
-                ref allow_internal_unstable,
-                allow_internal_unsafe,
-                local_inner_macros,
-                unstable_feature,
-                edition,
-                ..
-            } => {
-                if let Err(dummy_span) = validate_and_set_expn_info(self, def_info.map(|(_, s)| s),
-                                                                    allow_internal_unstable.clone(),
-                                                                    allow_internal_unsafe,
-                                                                    local_inner_macros,
-                                                                    unstable_feature,
-                                                                    edition) {
+        let opt_expanded = match &ext.kind {
+            SyntaxExtensionKind::LegacyBang(expander) => {
+                if let Err(dummy_span) = validate_and_set_expn_info(self) {
                     dummy_span
                 } else {
                     kind.make_from(expander.expand(
                         self.cx,
                         span,
                         mac.node.stream(),
-                        def_info.map(|(_, s)| s),
+                        ext.def_info.map(|(_, s)| s),
                     ))
                 }
             }
 
-            SyntaxExtension::Attr(..) |
-            SyntaxExtension::LegacyAttr(..) |
-            SyntaxExtension::NonMacroAttr { .. } => {
+            SyntaxExtensionKind::Attr(..) |
+            SyntaxExtensionKind::LegacyAttr(..) |
+            SyntaxExtensionKind::NonMacroAttr { .. } => {
                 self.cx.span_err(path.span,
                                  &format!("`{}` can only be used in attributes", path));
                 self.cx.trace_macros_diag();
                 kind.dummy(span)
             }
 
-            SyntaxExtension::Derive(..) | SyntaxExtension::LegacyDerive(..) => {
+            SyntaxExtensionKind::Derive(..) | SyntaxExtensionKind::LegacyDerive(..) => {
                 self.cx.span_err(path.span, &format!("`{}` is a derive macro", path));
                 self.cx.trace_macros_diag();
                 kind.dummy(span)
             }
 
-            SyntaxExtension::Bang { ref expander, ref allow_internal_unstable, edition } => {
+            SyntaxExtensionKind::Bang(expander) => {
                 if ident.name != kw::Invalid {
                     let msg =
                         format!("macro {}! expects no ident argument, given '{}'", path, ident);
@@ -798,19 +757,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     kind.dummy(span)
                 } else {
                     self.gate_proc_macro_expansion_kind(span, kind);
-                    invoc.expansion_data.mark.set_expn_info(ExpnInfo {
-                        call_site: span,
-                        // FIXME procedural macros do not have proper span info
-                        // yet, when they do, we should use it here.
-                        def_site: None,
-                        format: macro_bang_format(path),
-                        // FIXME probably want to follow macro_rules macros here.
-                        allow_internal_unstable: allow_internal_unstable.clone(),
-                        allow_internal_unsafe: false,
-                        local_inner_macros: false,
-                        edition,
-                    });
-
+                    let expn_info = ext.expn_info(span, &fast_print_path(path));
+                    invoc.expansion_data.mark.set_expn_info(expn_info);
                     let tok_result = expander.expand(self.cx, span, mac.node.stream());
                     let result = self.parse_ast_fragment(tok_result, kind, path, span);
                     self.gate_proc_macro_expansion(span, &result);
@@ -867,55 +815,23 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             return None;
         }
 
-        let pretty_name = Symbol::intern(&format!("derive({})", path));
-        let span = path.span;
-        let attr = ast::Attribute {
-            path, span,
-            tokens: TokenStream::empty(),
-            // irrelevant:
-            id: ast::AttrId(0), style: ast::AttrStyle::Outer, is_sugared_doc: false,
-        };
-
-        let mut expn_info = ExpnInfo {
-            call_site: span,
-            def_site: None,
-            format: MacroAttribute(pretty_name),
-            allow_internal_unstable: None,
-            allow_internal_unsafe: false,
-            local_inner_macros: false,
-            edition: ext.edition(self.cx.parse_sess.edition),
-        };
-
-        match ext {
-            SyntaxExtension::Derive(expander, ..) | SyntaxExtension::LegacyDerive(expander) => {
-                let meta = match ext {
-                    SyntaxExtension::Derive(..) => ast::MetaItem { // FIXME(jseyfried) avoid this
-                        path: Path::from_ident(Ident::invalid()),
-                        span: DUMMY_SP,
-                        node: ast::MetaItemKind::Word,
-                    },
-                    _ => {
-                        expn_info.allow_internal_unstable = Some(vec![
-                            sym::rustc_attrs,
-                            Symbol::intern("derive_clone_copy"),
-                            Symbol::intern("derive_eq"),
-                            // RustcDeserialize and RustcSerialize
-                            Symbol::intern("libstd_sys_internals"),
-                        ].into());
-                        attr.meta()?
-                    }
-                };
-
+        match &ext.kind {
+            SyntaxExtensionKind::Derive(expander) |
+            SyntaxExtensionKind::LegacyDerive(expander) => {
+                let expn_info =
+                    ext.expn_info(path.span, &format!("derive({})", fast_print_path(&path)));
                 invoc.expansion_data.mark.set_expn_info(expn_info);
-                let span = span.with_ctxt(self.cx.backtrace());
+
+                let meta = ast::MetaItem { node: ast::MetaItemKind::Word, span: path.span, path };
+                let span = meta.span.with_ctxt(self.cx.backtrace());
                 let items = expander.expand(self.cx, span, &meta, item);
                 Some(invoc.fragment_kind.expect_from_annotatables(items))
             }
             _ => {
-                let msg = &format!("macro `{}` may not be used for derive attributes", attr.path);
-                self.cx.span_err(span, msg);
+                let msg = &format!("macro `{}` may not be used for derive attributes", path);
+                self.cx.span_err(path.span, msg);
                 self.cx.trace_macros_diag();
-                invoc.fragment_kind.dummy(span)
+                invoc.fragment_kind.dummy(path.span)
             }
         }
     }
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index 22745a1a76d..7f051c260ec 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -1,6 +1,7 @@
 use crate::{ast, attr};
 use crate::edition::Edition;
-use crate::ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension, TTMacroExpander};
+use crate::ext::base::{SyntaxExtension, SyntaxExtensionKind};
+use crate::ext::base::{DummyResult, ExtCtxt, MacResult, TTMacroExpander};
 use crate::ext::expand::{AstFragment, AstFragmentKind};
 use crate::ext::hygiene::Transparency;
 use crate::ext::tt::macro_parser::{Success, Error, Failure};
@@ -376,7 +377,7 @@ pub fn compile(
         valid,
     });
 
-    let transparency = if attr::contains_name(&def.attrs, sym::rustc_transparent_macro) {
+    let default_transparency = if attr::contains_name(&def.attrs, sym::rustc_transparent_macro) {
         Transparency::Transparent
     } else if body.legacy {
         Transparency::SemiTransparent
@@ -426,14 +427,15 @@ pub fn compile(
         }
     });
 
-    SyntaxExtension::LegacyBang {
-        expander,
+    SyntaxExtension {
+        kind: SyntaxExtensionKind::LegacyBang(expander),
         def_info: Some((def.id, def.span)),
-        transparency,
+        default_transparency,
         allow_internal_unstable,
         allow_internal_unsafe,
         local_inner_macros,
         unstable_feature,
+        helper_attrs: Vec::new(),
         edition,
     }
 }
diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs
index eea94f0d194..9072ad7b30f 100644
--- a/src/libsyntax/std_inject.rs
+++ b/src/libsyntax/std_inject.rs
@@ -20,7 +20,7 @@ fn ignored_span(sp: Span, edition: Edition) -> Span {
         call_site: DUMMY_SP,
         def_site: None,
         format: MacroAttribute(Symbol::intern("std_inject")),
-        allow_internal_unstable: Some(vec![sym::prelude_import].into()),
+        allow_internal_unstable: Some([sym::prelude_import][..].into()),
         allow_internal_unsafe: false,
         local_inner_macros: false,
         edition,
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index cbaf12529c1..0e1b10c14f1 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -284,7 +284,7 @@ fn generate_test_harness(sess: &ParseSess,
         call_site: DUMMY_SP,
         def_site: None,
         format: MacroAttribute(sym::test_case),
-        allow_internal_unstable: Some(vec![sym::main, sym::test, sym::rustc_attrs].into()),
+        allow_internal_unstable: Some([sym::main, sym::test, sym::rustc_attrs][..].into()),
         allow_internal_unsafe: false,
         local_inner_macros: false,
         edition: sess.edition,
diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs
index cf54eacc3d4..e4a413dda09 100644
--- a/src/libsyntax_ext/deriving/mod.rs
+++ b/src/libsyntax_ext/deriving/mod.rs
@@ -2,7 +2,9 @@
 
 use rustc_data_structures::sync::Lrc;
 use syntax::ast::{self, MetaItem};
-use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension, Resolver, MultiItemModifier};
+use syntax::edition::Edition;
+use syntax::ext::base::{Annotatable, ExtCtxt, Resolver, MultiItemModifier};
+use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind};
 use syntax::ext::build::AstBuilder;
 use syntax::ext::hygiene::{Mark, SyntaxContext};
 use syntax::ptr::P;
@@ -67,11 +69,24 @@ macro_rules! derive_traits {
             }
         }
 
-        pub fn register_builtin_derives(resolver: &mut dyn Resolver) {
+        pub fn register_builtin_derives(resolver: &mut dyn Resolver, edition: Edition) {
+            let allow_internal_unstable = Some([
+                sym::rustc_attrs,
+                Symbol::intern("derive_clone_copy"),
+                Symbol::intern("derive_eq"),
+                Symbol::intern("libstd_sys_internals"), // RustcDeserialize and RustcSerialize
+            ][..].into());
+
             $(
                 resolver.add_builtin(
                     ast::Ident::with_empty_ctxt(Symbol::intern($name)),
-                    Lrc::new(SyntaxExtension::LegacyDerive(Box::new(BuiltinDerive($func))))
+                    Lrc::new(SyntaxExtension {
+                        allow_internal_unstable: allow_internal_unstable.clone(),
+                        ..SyntaxExtension::default(
+                            SyntaxExtensionKind::LegacyDerive(Box::new(BuiltinDerive($func))),
+                            edition,
+                        )
+                    }),
                 );
             )*
         }
diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs
index 3dd17207cb8..d29d93a8678 100644
--- a/src/libsyntax_ext/lib.rs
+++ b/src/libsyntax_ext/lib.rs
@@ -43,32 +43,31 @@ pub mod proc_macro_impl;
 use rustc_data_structures::sync::Lrc;
 use syntax::ast;
 
-use syntax::ext::base::{MacroExpanderFn, NamedSyntaxExtension, SyntaxExtension};
-use syntax::ext::hygiene::Transparency;
+use syntax::ext::base::MacroExpanderFn;
+use syntax::ext::base::{NamedSyntaxExtension, SyntaxExtension, SyntaxExtensionKind};
 use syntax::edition::Edition;
 use syntax::symbol::{sym, Symbol};
 
 pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver,
                          user_exts: Vec<NamedSyntaxExtension>,
                          edition: Edition) {
-    deriving::register_builtin_derives(resolver);
+    deriving::register_builtin_derives(resolver, edition);
 
     let mut register = |name, ext| {
         resolver.add_builtin(ast::Ident::with_empty_ctxt(name), Lrc::new(ext));
     };
     macro_rules! register {
         ($( $name:ident: $f:expr, )*) => { $(
-            register(Symbol::intern(stringify!($name)),
-                     SyntaxExtension::LegacyBang {
-                        expander: Box::new($f as MacroExpanderFn),
-                        def_info: None,
-                        transparency: Transparency::SemiTransparent,
-                        allow_internal_unstable: None,
-                        allow_internal_unsafe: false,
-                        local_inner_macros: false,
-                        unstable_feature: None,
-                        edition,
-                    });
+            register(Symbol::intern(stringify!($name)), SyntaxExtension::default(
+                SyntaxExtensionKind::LegacyBang(Box::new($f as MacroExpanderFn)), edition
+            ));
+        )* }
+    }
+    macro_rules! register_attr {
+        ($( $name:ident: $f:expr, )*) => { $(
+            register(Symbol::intern(stringify!($name)), SyntaxExtension::default(
+                SyntaxExtensionKind::LegacyAttr(Box::new($f)), edition
+            ));
         )* }
     }
 
@@ -97,33 +96,25 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver,
         assert: assert::expand_assert,
     }
 
-    register(sym::test_case, SyntaxExtension::LegacyAttr(Box::new(test_case::expand)));
-    register(sym::test, SyntaxExtension::LegacyAttr(Box::new(test::expand_test)));
-    register(sym::bench, SyntaxExtension::LegacyAttr(Box::new(test::expand_bench)));
+    register_attr! {
+        test_case: test_case::expand,
+        test: test::expand_test,
+        bench: test::expand_bench,
+    }
 
     // format_args uses `unstable` things internally.
-    register(Symbol::intern("format_args"),
-             SyntaxExtension::LegacyBang {
-                expander: Box::new(format::expand_format_args),
-                def_info: None,
-                transparency: Transparency::SemiTransparent,
-                allow_internal_unstable: Some(vec![sym::fmt_internals].into()),
-                allow_internal_unsafe: false,
-                local_inner_macros: false,
-                unstable_feature: None,
-                edition,
-            });
-    register(sym::format_args_nl,
-             SyntaxExtension::LegacyBang {
-                 expander: Box::new(format::expand_format_args_nl),
-                 def_info: None,
-                 transparency: Transparency::SemiTransparent,
-                 allow_internal_unstable: Some(vec![sym::fmt_internals].into()),
-                 allow_internal_unsafe: false,
-                 local_inner_macros: false,
-                 unstable_feature: None,
-                 edition,
-             });
+    register(Symbol::intern("format_args"), SyntaxExtension {
+        allow_internal_unstable: Some([sym::fmt_internals][..].into()),
+        ..SyntaxExtension::default(
+            SyntaxExtensionKind::LegacyBang(Box::new(format::expand_format_args)), edition
+        )
+    });
+    register(sym::format_args_nl, SyntaxExtension {
+        allow_internal_unstable: Some([sym::fmt_internals][..].into()),
+        ..SyntaxExtension::default(
+            SyntaxExtensionKind::LegacyBang(Box::new(format::expand_format_args_nl)), edition
+        )
+    });
 
     for (name, ext) in user_exts {
         register(name, ext);
diff --git a/src/libsyntax_ext/proc_macro_decls.rs b/src/libsyntax_ext/proc_macro_decls.rs
index 29297aa913e..cdef5c6a9f4 100644
--- a/src/libsyntax_ext/proc_macro_decls.rs
+++ b/src/libsyntax_ext/proc_macro_decls.rs
@@ -351,10 +351,9 @@ fn mk_decls(
         call_site: DUMMY_SP,
         def_site: None,
         format: MacroAttribute(sym::proc_macro),
-        allow_internal_unstable: Some(vec![
-            sym::rustc_attrs,
-            Symbol::intern("proc_macro_internals"),
-        ].into()),
+        allow_internal_unstable: Some([
+            sym::rustc_attrs, Symbol::intern("proc_macro_internals")
+        ][..].into()),
         allow_internal_unsafe: false,
         local_inner_macros: false,
         edition: cx.parse_sess.edition,
diff --git a/src/libsyntax_ext/test.rs b/src/libsyntax_ext/test.rs
index c20dc6cb2d7..a8c8456a3bc 100644
--- a/src/libsyntax_ext/test.rs
+++ b/src/libsyntax_ext/test.rs
@@ -66,7 +66,7 @@ pub fn expand_test_or_bench(
             call_site: DUMMY_SP,
             def_site: None,
             format: MacroAttribute(sym::test),
-            allow_internal_unstable: Some(vec![sym::rustc_attrs, sym::test].into()),
+            allow_internal_unstable: Some([sym::rustc_attrs, sym::test][..].into()),
             allow_internal_unsafe: false,
             local_inner_macros: false,
             edition: cx.parse_sess.edition,
diff --git a/src/libsyntax_ext/test_case.rs b/src/libsyntax_ext/test_case.rs
index cffecdd0f18..ce17cf2a6e7 100644
--- a/src/libsyntax_ext/test_case.rs
+++ b/src/libsyntax_ext/test_case.rs
@@ -41,7 +41,7 @@ pub fn expand(
             call_site: DUMMY_SP,
             def_site: None,
             format: MacroAttribute(sym::test_case),
-            allow_internal_unstable: Some(vec![sym::test, sym::rustc_attrs].into()),
+            allow_internal_unstable: Some([sym::test, sym::rustc_attrs][..].into()),
             allow_internal_unsafe: false,
             local_inner_macros: false,
             edition: ecx.parse_sess.edition,
diff --git a/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs b/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs
index 330459fc08f..4cf8a4e33c5 100644
--- a/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs
@@ -11,8 +11,8 @@ extern crate rustc_plugin;
 use std::borrow::ToOwned;
 use syntax::ast;
 use syntax::ext::build::AstBuilder;
-use syntax::ext::base::{SyntaxExtension, TTMacroExpander, ExtCtxt, MacResult, MacEager};
-use syntax::ext::hygiene::Transparency;
+use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind};
+use syntax::ext::base::{TTMacroExpander, ExtCtxt, MacResult, MacEager};
 use syntax::print::pprust;
 use syntax::symbol::Symbol;
 use syntax_pos::Span;
@@ -38,15 +38,7 @@ impl TTMacroExpander for Expander {
 #[plugin_registrar]
 pub fn plugin_registrar(reg: &mut Registry) {
     let args = reg.args().to_owned();
-    reg.register_syntax_extension(Symbol::intern("plugin_args"),
-        SyntaxExtension::LegacyBang {
-            expander: Box::new(Expander { args: args, }),
-            def_info: None,
-            transparency: Transparency::SemiTransparent,
-            allow_internal_unstable: None,
-            allow_internal_unsafe: false,
-            local_inner_macros: false,
-            unstable_feature: None,
-            edition: reg.sess.edition(),
-        });
+    reg.register_syntax_extension(Symbol::intern("plugin_args"), SyntaxExtension::default(
+        SyntaxExtensionKind::LegacyBang(Box::new(Expander { args })), reg.sess.edition()
+    ));
 }