From a4a07e00ced90e076dbadd8b350db527bcc588bd Mon Sep 17 00:00:00 2001
From: Tobia <tobia.conforto@gruppo4.it>
Date: Mon, 1 Apr 2019 18:16:03 +0900
Subject: [PATCH 01/20] Replaced linear token counting macros with optimized
 implementation

---
 src/librustc/hir/map/definitions.rs | 12 ++++++++++--
 src/libserialize/serialize.rs       | 17 ++++++++++++-----
 2 files changed, 22 insertions(+), 7 deletions(-)

diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index 1006d813e65ed..c72edb6cc6d72 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -696,9 +696,17 @@ impl DefPathData {
     }
 }
 
+/// Evaluates to the number of tokens passed to it.
+///
+/// Logarithmic counting: every one or two recursive expansions, the number of
+/// tokens to count is divided by two, instead of being reduced by one.
+/// Therefore, the recursion depth is the binary logarithm of the number of
+/// tokens to count, and the expanded tree is likewise very small.
 macro_rules! count {
-    () => (0usize);
-    ( $x:tt $($xs:tt)* ) => (1usize + count!($($xs)*));
+    ()                     => (0usize);
+    ($one:tt)              => (1usize);
+    ($($pairs:tt $_p:tt)*) => (count!($($pairs)*) << 1usize);
+    ($odd:tt $($rest:tt)*) => (count!($($rest)*) | 1usize);
 }
 
 // We define the GlobalMetaDataKind enum with this macro because we want to
diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs
index cf948078b08c5..d53891828f1c0 100644
--- a/src/libserialize/serialize.rs
+++ b/src/libserialize/serialize.rs
@@ -723,10 +723,17 @@ macro_rules! peel {
     ($name:ident, $($other:ident,)*) => (tuple! { $($other,)* })
 }
 
-/// Evaluates to the number of identifiers passed to it, for example: `count_idents!(a, b, c) == 3
-macro_rules! count_idents {
-    () => { 0 };
-    ($_i:ident, $($rest:ident,)*) => { 1 + count_idents!($($rest,)*) }
+/// Evaluates to the number of tokens passed to it.
+///
+/// Logarithmic counting: every one or two recursive expansions, the number of
+/// tokens to count is divided by two, instead of being reduced by one.
+/// Therefore, the recursion depth is the binary logarithm of the number of
+/// tokens to count, and the expanded tree is likewise very small.
+macro_rules! count {
+    ()                     => (0usize);
+    ($one:tt)              => (1usize);
+    ($($pairs:tt $_p:tt)*) => (count!($($pairs)*) << 1usize);
+    ($odd:tt $($rest:tt)*) => (count!($($rest)*) | 1usize);
 }
 
 macro_rules! tuple {
@@ -735,7 +742,7 @@ macro_rules! tuple {
         impl<$($name:Decodable),*> Decodable for ($($name,)*) {
             #[allow(non_snake_case)]
             fn decode<D: Decoder>(d: &mut D) -> Result<($($name,)*), D::Error> {
-                let len: usize = count_idents!($($name,)*);
+                let len: usize = count!($($name)*);
                 d.read_tuple(len, |d| {
                     let mut i = 0;
                     let ret = ($(d.read_tuple_arg({ i+=1; i-1 }, |d| -> Result<$name, D::Error> {

From 97a5173df4e8ecb274117476e613f4af1e0f6324 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Thu, 6 Jun 2019 21:10:16 +0300
Subject: [PATCH 02/20] syntax: Remove `SyntaxExtension::IdentTT` and
 `IdentMacroExpander`

---
 src/librustc_plugin/registry.rs |  5 +----
 src/libsyntax/ext/base.rs       | 38 ---------------------------------
 src/libsyntax/ext/expand.rs     | 22 -------------------
 3 files changed, 1 insertion(+), 64 deletions(-)

diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs
index 2ed6f868fa1ee..967fdcd2e7d41 100644
--- a/src/librustc_plugin/registry.rs
+++ b/src/librustc_plugin/registry.rs
@@ -4,7 +4,7 @@ use rustc::lint::{EarlyLintPassObject, LateLintPassObject, LintId, Lint};
 use rustc::session::Session;
 use rustc::util::nodemap::FxHashMap;
 
-use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT, IdentTT};
+use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT};
 use syntax::ext::base::MacroExpanderFn;
 use syntax::symbol::{Symbol, sym};
 use syntax::ast;
@@ -109,9 +109,6 @@ impl<'a> Registry<'a> {
                     edition,
                 }
             }
-            IdentTT { expander, span: _, allow_internal_unstable } => {
-                IdentTT { expander, span: Some(self.krate_span), allow_internal_unstable }
-            }
             _ => extension,
         }));
     }
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 4b5b9ff7bbeee..e9a1e26038c47 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -285,34 +285,6 @@ impl<F> TTMacroExpander for F
     }
 }
 
-pub trait IdentMacroExpander {
-    fn expand<'cx>(&self,
-                   cx: &'cx mut ExtCtxt<'_>,
-                   sp: Span,
-                   ident: ast::Ident,
-                   token_tree: Vec<tokenstream::TokenTree>)
-                   -> Box<dyn MacResult+'cx>;
-}
-
-pub type IdentMacroExpanderFn =
-    for<'cx> fn(&'cx mut ExtCtxt<'_>, Span, ast::Ident, Vec<tokenstream::TokenTree>)
-                -> Box<dyn MacResult+'cx>;
-
-impl<F> IdentMacroExpander for F
-    where F : for<'cx> Fn(&'cx mut ExtCtxt<'_>, Span, ast::Ident,
-                          Vec<tokenstream::TokenTree>) -> Box<dyn MacResult+'cx>
-{
-    fn expand<'cx>(&self,
-                   cx: &'cx mut ExtCtxt<'_>,
-                   sp: Span,
-                   ident: ast::Ident,
-                   token_tree: Vec<tokenstream::TokenTree>)
-                   -> Box<dyn MacResult+'cx>
-    {
-        (*self)(cx, sp, ident, token_tree)
-    }
-}
-
 // Use a macro because forwarding to a simple function has type system issues
 macro_rules! make_stmts_default {
     ($me:expr) => {
@@ -655,14 +627,6 @@ pub enum SyntaxExtension {
         edition: Edition,
     },
 
-    /// A function-like syntax extension that has an extra ident before
-    /// the block.
-    IdentTT {
-        expander: Box<dyn IdentMacroExpander + sync::Sync + sync::Send>,
-        span: Option<Span>,
-        allow_internal_unstable: Option<Lrc<[Symbol]>>,
-    },
-
     /// An attribute-like procedural macro. TokenStream -> TokenStream.
     /// The input is the annotated item.
     /// Allows generating code to implement a Trait for a given struct
@@ -688,7 +652,6 @@ impl SyntaxExtension {
         match *self {
             SyntaxExtension::DeclMacro { .. } |
             SyntaxExtension::NormalTT { .. } |
-            SyntaxExtension::IdentTT { .. } |
             SyntaxExtension::ProcMacro { .. } =>
                 MacroKind::Bang,
             SyntaxExtension::NonMacroAttr { .. } |
@@ -722,7 +685,6 @@ impl SyntaxExtension {
             SyntaxExtension::ProcMacroDerive(.., edition) => edition,
             // Unstable legacy stuff
             SyntaxExtension::NonMacroAttr { .. } |
-            SyntaxExtension::IdentTT { .. } |
             SyntaxExtension::MultiDecorator(..) |
             SyntaxExtension::MultiModifier(..) |
             SyntaxExtension::BuiltinDerive(..) => default_edition,
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index c2a73b662c680..bb69a758dcdc8 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -791,28 +791,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 }
             }
 
-            IdentTT { ref expander, span: tt_span, ref allow_internal_unstable } => {
-                if ident.name == kw::Invalid {
-                    self.cx.span_err(path.span,
-                                    &format!("macro {}! expects an ident argument", path));
-                    self.cx.trace_macros_diag();
-                    kind.dummy(span)
-                } else {
-                    invoc.expansion_data.mark.set_expn_info(ExpnInfo {
-                        call_site: span,
-                        def_site: tt_span,
-                        format: macro_bang_format(path),
-                        allow_internal_unstable: allow_internal_unstable.clone(),
-                        allow_internal_unsafe: false,
-                        local_inner_macros: false,
-                        edition: self.cx.parse_sess.edition,
-                    });
-
-                    let input: Vec<_> = mac.node.stream().into_trees().collect();
-                    kind.make_from(expander.expand(self.cx, span, ident, input))
-                }
-            }
-
             MultiDecorator(..) | MultiModifier(..) |
             AttrProcMacro(..) | SyntaxExtension::NonMacroAttr { .. } => {
                 self.cx.span_err(path.span,

From 4419af8ae9939e208cc47387e3bdfb286f922f12 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Thu, 6 Jun 2019 21:38:27 +0300
Subject: [PATCH 03/20] Remove `SyntaxExtension::MultiDecorator` and
 `MultiItemDecorator`

---
 src/libsyntax/ext/base.rs                     | 33 --------
 src/libsyntax/ext/expand.rs                   | 11 +--
 .../auxiliary/custom-derive-partial-eq.rs     | 71 ----------------
 .../auxiliary/custom-derive-plugin-attr.rs    | 84 -------------------
 .../auxiliary/custom-derive-plugin.rs         | 76 -----------------
 .../custom-derive-partial-eq.rs               | 10 ---
 .../run-pass-fulldeps/derive-totalsum-attr.rs | 64 --------------
 src/test/run-pass-fulldeps/derive-totalsum.rs | 49 -----------
 src/test/run-pass-fulldeps/issue-40663.rs     | 13 ---
 9 files changed, 1 insertion(+), 410 deletions(-)
 delete mode 100644 src/test/run-pass-fulldeps/auxiliary/custom-derive-partial-eq.rs
 delete mode 100644 src/test/run-pass-fulldeps/auxiliary/custom-derive-plugin-attr.rs
 delete mode 100644 src/test/run-pass-fulldeps/auxiliary/custom-derive-plugin.rs
 delete mode 100644 src/test/run-pass-fulldeps/custom-derive-partial-eq.rs
 delete mode 100644 src/test/run-pass-fulldeps/derive-totalsum-attr.rs
 delete mode 100644 src/test/run-pass-fulldeps/derive-totalsum.rs
 delete mode 100644 src/test/run-pass-fulldeps/issue-40663.rs

diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index e9a1e26038c47..1a716c3faef1d 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -137,29 +137,6 @@ impl Annotatable {
     }
 }
 
-// A more flexible ItemDecorator.
-pub trait MultiItemDecorator {
-    fn expand(&self,
-              ecx: &mut ExtCtxt<'_>,
-              sp: Span,
-              meta_item: &ast::MetaItem,
-              item: &Annotatable,
-              push: &mut dyn FnMut(Annotatable));
-}
-
-impl<F> MultiItemDecorator for F
-    where F : Fn(&mut ExtCtxt<'_>, Span, &ast::MetaItem, &Annotatable, &mut dyn FnMut(Annotatable))
-{
-    fn expand(&self,
-              ecx: &mut ExtCtxt<'_>,
-              sp: Span,
-              meta_item: &ast::MetaItem,
-              item: &Annotatable,
-              push: &mut dyn FnMut(Annotatable)) {
-        (*self)(ecx, sp, meta_item, item, push)
-    }
-}
-
 // `meta_item` is the annotation, and `item` is the item being modified.
 // FIXME Decorators should follow the same pattern too.
 pub trait MultiItemModifier {
@@ -578,14 +555,6 @@ pub enum SyntaxExtension {
     /// A trivial "extension" that does nothing, only keeps the attribute and marks it as known.
     NonMacroAttr { mark_used: bool },
 
-    /// A syntax extension that is attached to an item and creates new items
-    /// based upon it.
-    ///
-    /// `#[derive(...)]` is a `MultiItemDecorator`.
-    ///
-    /// Prefer ProcMacro or MultiModifier since they are more flexible.
-    MultiDecorator(Box<dyn MultiItemDecorator + sync::Sync + sync::Send>),
-
     /// A syntax extension that is attached to an item and modifies it
     /// in-place. Also allows decoration, i.e., creating new items.
     MultiModifier(Box<dyn MultiItemModifier + sync::Sync + sync::Send>),
@@ -655,7 +624,6 @@ impl SyntaxExtension {
             SyntaxExtension::ProcMacro { .. } =>
                 MacroKind::Bang,
             SyntaxExtension::NonMacroAttr { .. } |
-            SyntaxExtension::MultiDecorator(..) |
             SyntaxExtension::MultiModifier(..) |
             SyntaxExtension::AttrProcMacro(..) =>
                 MacroKind::Attr,
@@ -685,7 +653,6 @@ impl SyntaxExtension {
             SyntaxExtension::ProcMacroDerive(.., edition) => edition,
             // Unstable legacy stuff
             SyntaxExtension::NonMacroAttr { .. } |
-            SyntaxExtension::MultiDecorator(..) |
             SyntaxExtension::MultiModifier(..) |
             SyntaxExtension::BuiltinDerive(..) => default_edition,
         }
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index bb69a758dcdc8..7d2928ef1807b 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -575,14 +575,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 let item = mac.expand(self.cx, attr.span, &meta, item);
                 Some(invoc.fragment_kind.expect_from_annotatables(item))
             }
-            MultiDecorator(ref mac) => {
-                let mut items = Vec::new();
-                let meta = attr.parse_meta(self.cx.parse_sess)
-                               .expect("derive meta should already have been parsed");
-                mac.expand(self.cx, attr.span, &meta, &item, &mut |item| items.push(item));
-                items.push(item);
-                Some(invoc.fragment_kind.expect_from_annotatables(items))
-            }
             AttrProcMacro(ref mac, ..) => {
                 self.gate_proc_macro_attr_item(attr.span, &item);
                 let item_tok = TokenTree::Token(DUMMY_SP, Token::Interpolated(Lrc::new(match item {
@@ -791,8 +783,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 }
             }
 
-            MultiDecorator(..) | MultiModifier(..) |
-            AttrProcMacro(..) | SyntaxExtension::NonMacroAttr { .. } => {
+            MultiModifier(..) | AttrProcMacro(..) | SyntaxExtension::NonMacroAttr { .. } => {
                 self.cx.span_err(path.span,
                                  &format!("`{}` can only be used in attributes", path));
                 self.cx.trace_macros_diag();
diff --git a/src/test/run-pass-fulldeps/auxiliary/custom-derive-partial-eq.rs b/src/test/run-pass-fulldeps/auxiliary/custom-derive-partial-eq.rs
deleted file mode 100644
index 4d6ff47a3ee91..0000000000000
--- a/src/test/run-pass-fulldeps/auxiliary/custom-derive-partial-eq.rs
+++ /dev/null
@@ -1,71 +0,0 @@
-// force-host
-
-#![feature(plugin_registrar, rustc_private)]
-
-extern crate syntax;
-extern crate syntax_ext;
-extern crate rustc_plugin;
-
-use syntax_ext::deriving;
-use deriving::generic::*;
-use deriving::generic::ty::*;
-
-use rustc_plugin::Registry;
-use syntax::ast::*;
-use syntax::source_map::Span;
-use syntax::ext::base::*;
-use syntax::ext::build::AstBuilder;
-use syntax::symbol::Symbol;
-use syntax::ptr::P;
-
-#[plugin_registrar]
-pub fn plugin_registrar(reg: &mut Registry) {
-    reg.register_syntax_extension(Symbol::intern("derive_CustomPartialEq"),
-                                  MultiDecorator(Box::new(expand_deriving_partial_eq)));
-}
-
-fn expand_deriving_partial_eq(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable,
-                              push: &mut FnMut(Annotatable)) {
-    // structures are equal if all fields are equal, and non equal, if
-    // any fields are not equal or if the enum variants are different
-    fn cs_eq(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> {
-        cs_fold(true,
-                |cx, span, subexpr, self_f, other_fs| {
-                    let other_f = (other_fs.len(), other_fs.get(0)).1.unwrap();
-                    let eq = cx.expr_binary(span, BinOpKind::Eq, self_f, other_f.clone());
-                    cx.expr_binary(span, BinOpKind::And, subexpr, eq)
-                },
-                cx.expr_bool(span, true),
-                Box::new(|cx, span, _, _| cx.expr_bool(span, false)),
-                cx,
-                span,
-                substr)
-    }
-
-    let inline = cx.meta_word(span, Symbol::intern("inline"));
-    let attrs = vec![cx.attribute(span, inline)];
-    let methods = vec![MethodDef {
-        name: "eq",
-        generics: LifetimeBounds::empty(),
-        explicit_self: borrowed_explicit_self(),
-        args: vec![(borrowed_self(), "other")],
-        ret_ty: Literal(deriving::generic::ty::Path::new_local("bool")),
-        attributes: attrs,
-        is_unsafe: false,
-        unify_fieldless_variants: true,
-        combine_substructure: combine_substructure(Box::new(cs_eq)),
-    }];
-
-    let trait_def = TraitDef {
-        span: span,
-        attributes: Vec::new(),
-        path: deriving::generic::ty::Path::new(vec!["cmp", "PartialEq"]),
-        additional_bounds: Vec::new(),
-        generics: LifetimeBounds::empty(),
-        is_unsafe: false,
-        supports_unions: false,
-        methods: methods,
-        associated_types: Vec::new(),
-    };
-    trait_def.expand(cx, mitem, item, push)
-}
diff --git a/src/test/run-pass-fulldeps/auxiliary/custom-derive-plugin-attr.rs b/src/test/run-pass-fulldeps/auxiliary/custom-derive-plugin-attr.rs
deleted file mode 100644
index c6b33fbc75ee2..0000000000000
--- a/src/test/run-pass-fulldeps/auxiliary/custom-derive-plugin-attr.rs
+++ /dev/null
@@ -1,84 +0,0 @@
-// force-host
-
-#![feature(plugin_registrar)]
-#![feature(box_syntax)]
-#![feature(rustc_private)]
-
-extern crate syntax;
-extern crate syntax_ext;
-extern crate syntax_pos;
-extern crate rustc;
-extern crate rustc_plugin;
-
-use syntax::ast;
-use syntax::attr;
-use syntax::ext::base::{MultiDecorator, ExtCtxt, Annotatable};
-use syntax::ext::build::AstBuilder;
-use syntax::symbol::{Symbol, sym};
-use syntax::ptr::P;
-use syntax_ext::deriving::generic::{TraitDef, MethodDef, combine_substructure};
-use syntax_ext::deriving::generic::{Substructure, Struct, EnumMatching};
-use syntax_ext::deriving::generic::ty::{Literal, LifetimeBounds, Path, borrowed_explicit_self};
-use syntax_pos::Span;
-use rustc_plugin::Registry;
-
-#[plugin_registrar]
-pub fn plugin_registrar(reg: &mut Registry) {
-    reg.register_syntax_extension(
-        Symbol::intern("rustc_derive_TotalSum"),
-        MultiDecorator(box expand));
-}
-
-fn expand(cx: &mut ExtCtxt,
-          span: Span,
-          mitem: &ast::MetaItem,
-          item: &Annotatable,
-          push: &mut FnMut(Annotatable)) {
-    let trait_def = TraitDef {
-        span: span,
-        attributes: vec![],
-        path: Path::new_local("TotalSum"),
-        additional_bounds: vec![],
-        generics: LifetimeBounds::empty(),
-        associated_types: vec![],
-        is_unsafe: false,
-        supports_unions: false,
-        methods: vec![
-            MethodDef {
-                name: "total_sum",
-                generics: LifetimeBounds::empty(),
-                explicit_self: borrowed_explicit_self(),
-                args: vec![],
-                ret_ty: Literal(Path::new_local("isize")),
-                attributes: vec![],
-                is_unsafe: false,
-                unify_fieldless_variants: true,
-                combine_substructure: combine_substructure(Box::new(totalsum_substructure)),
-            },
-        ],
-    };
-
-    trait_def.expand(cx, mitem, item, push)
-}
-
-// Mostly copied from syntax::ext::deriving::hash
-/// Defines how the implementation for `trace()` is to be generated
-fn totalsum_substructure(cx: &mut ExtCtxt, trait_span: Span,
-                         substr: &Substructure) -> P<ast::Expr> {
-    let fields = match *substr.fields {
-        Struct(_, ref fs) | EnumMatching(.., ref fs) => fs,
-        _ => cx.span_bug(trait_span, "impossible substructure")
-    };
-
-    fields.iter().fold(cx.expr_isize(trait_span, 0), |acc, ref item| {
-        if attr::contains_name(&item.attrs, sym::ignore) {
-            acc
-        } else {
-            cx.expr_binary(item.span, ast::BinOpKind::Add, acc,
-                           cx.expr_method_call(item.span,
-                                               item.self_.clone(),
-                                               substr.method_ident,
-                                               Vec::new()))
-        }
-    })
-}
diff --git a/src/test/run-pass-fulldeps/auxiliary/custom-derive-plugin.rs b/src/test/run-pass-fulldeps/auxiliary/custom-derive-plugin.rs
deleted file mode 100644
index 874a0ec7c13fb..0000000000000
--- a/src/test/run-pass-fulldeps/auxiliary/custom-derive-plugin.rs
+++ /dev/null
@@ -1,76 +0,0 @@
-// force-host
-
-#![feature(plugin_registrar)]
-#![feature(box_syntax)]
-#![feature(rustc_private)]
-
-extern crate syntax;
-extern crate syntax_ext;
-extern crate syntax_pos;
-extern crate rustc;
-extern crate rustc_plugin;
-
-use syntax::ast;
-use syntax::ext::base::{MultiDecorator, ExtCtxt, Annotatable};
-use syntax::ext::build::AstBuilder;
-use syntax::symbol::Symbol;
-use syntax_ext::deriving::generic::{cs_fold, TraitDef, MethodDef, combine_substructure};
-use syntax_ext::deriving::generic::ty::{Literal, LifetimeBounds, Path, borrowed_explicit_self};
-use syntax_pos::Span;
-use rustc_plugin::Registry;
-
-#[plugin_registrar]
-pub fn plugin_registrar(reg: &mut Registry) {
-    reg.register_syntax_extension(
-        Symbol::intern("derive_TotalSum"),
-        MultiDecorator(box expand));
-
-    reg.register_syntax_extension(
-        Symbol::intern("derive_Nothing"),
-        MultiDecorator(box noop));
-}
-
-fn noop(_: &mut ExtCtxt, _: Span, _: &ast::MetaItem, _: &Annotatable, _: &mut FnMut(Annotatable)) {}
-
-fn expand(cx: &mut ExtCtxt,
-          span: Span,
-          mitem: &ast::MetaItem,
-          item: &Annotatable,
-          push: &mut FnMut(Annotatable)) {
-    let trait_def = TraitDef {
-        span: span,
-        attributes: vec![],
-        path: Path::new_local("TotalSum"),
-        additional_bounds: vec![],
-        generics: LifetimeBounds::empty(),
-        associated_types: vec![],
-        is_unsafe: false,
-        supports_unions: false,
-        methods: vec![
-            MethodDef {
-                name: "total_sum",
-                generics: LifetimeBounds::empty(),
-                explicit_self: borrowed_explicit_self(),
-                args: vec![],
-                ret_ty: Literal(Path::new_local("isize")),
-                attributes: vec![],
-                is_unsafe: false,
-                unify_fieldless_variants: true,
-                combine_substructure: combine_substructure(box |cx, span, substr| {
-                    let zero = cx.expr_isize(span, 0);
-                    cs_fold(false,
-                            |cx, span, subexpr, field, _| {
-                                cx.expr_binary(span, ast::BinOpKind::Add, subexpr,
-                                    cx.expr_method_call(span, field,
-                                        ast::Ident::from_str("total_sum"), vec![]))
-                            },
-                            zero,
-                            box |cx, span, _, _| { cx.span_bug(span, "wtf??"); },
-                            cx, span, substr)
-                }),
-            },
-        ],
-    };
-
-    trait_def.expand(cx, mitem, item, push)
-}
diff --git a/src/test/run-pass-fulldeps/custom-derive-partial-eq.rs b/src/test/run-pass-fulldeps/custom-derive-partial-eq.rs
deleted file mode 100644
index ac8fff4f6bfad..0000000000000
--- a/src/test/run-pass-fulldeps/custom-derive-partial-eq.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-// aux-build:custom-derive-partial-eq.rs
-// ignore-stage1
-#![feature(plugin)]
-#![plugin(custom_derive_partial_eq)]
-#![allow(unused)]
-
-#[derive_CustomPartialEq] // Check that this is not a stability error.
-enum E { V1, V2 }
-
-fn main() {}
diff --git a/src/test/run-pass-fulldeps/derive-totalsum-attr.rs b/src/test/run-pass-fulldeps/derive-totalsum-attr.rs
deleted file mode 100644
index 38eaa71dd6aba..0000000000000
--- a/src/test/run-pass-fulldeps/derive-totalsum-attr.rs
+++ /dev/null
@@ -1,64 +0,0 @@
-// aux-build:custom-derive-plugin-attr.rs
-// ignore-stage1
-
-#![feature(plugin, rustc_attrs)]
-#![plugin(custom_derive_plugin_attr)]
-
-trait TotalSum {
-    fn total_sum(&self) -> isize;
-}
-
-impl TotalSum for isize {
-    fn total_sum(&self) -> isize {
-        *self
-    }
-}
-
-struct Seven;
-
-impl TotalSum for Seven {
-    fn total_sum(&self) -> isize {
-        7
-    }
-}
-
-#[rustc_derive_TotalSum]
-struct Foo {
-    seven: Seven,
-    bar: Bar,
-    baz: isize,
-    #[ignore]
-    nan: NaN,
-}
-
-#[rustc_derive_TotalSum]
-struct Bar {
-    quux: isize,
-    bleh: isize,
-    #[ignore]
-    nan: NaN2
-}
-
-struct NaN;
-
-impl TotalSum for NaN {
-    fn total_sum(&self) -> isize {
-        panic!();
-    }
-}
-
-struct NaN2;
-
-pub fn main() {
-    let v = Foo {
-        seven: Seven,
-        bar: Bar {
-            quux: 9,
-            bleh: 3,
-            nan: NaN2
-        },
-        baz: 80,
-        nan: NaN
-    };
-    assert_eq!(v.total_sum(), 99);
-}
diff --git a/src/test/run-pass-fulldeps/derive-totalsum.rs b/src/test/run-pass-fulldeps/derive-totalsum.rs
deleted file mode 100644
index 2b0bb51d90aec..0000000000000
--- a/src/test/run-pass-fulldeps/derive-totalsum.rs
+++ /dev/null
@@ -1,49 +0,0 @@
-// aux-build:custom-derive-plugin.rs
-// ignore-stage1
-
-#![feature(plugin)]
-#![plugin(custom_derive_plugin)]
-
-trait TotalSum {
-    fn total_sum(&self) -> isize;
-}
-
-impl TotalSum for isize {
-    fn total_sum(&self) -> isize {
-        *self
-    }
-}
-
-struct Seven;
-
-impl TotalSum for Seven {
-    fn total_sum(&self) -> isize {
-        7
-    }
-}
-
-#[derive_TotalSum]
-struct Foo {
-    seven: Seven,
-    bar: Bar,
-    baz: isize,
-}
-
-#[derive_TotalSum]
-struct Bar {
-    quux: isize,
-    bleh: isize,
-}
-
-
-pub fn main() {
-    let v = Foo {
-        seven: Seven,
-        bar: Bar {
-            quux: 9,
-            bleh: 3,
-        },
-        baz: 80,
-    };
-    assert_eq!(v.total_sum(), 99);
-}
diff --git a/src/test/run-pass-fulldeps/issue-40663.rs b/src/test/run-pass-fulldeps/issue-40663.rs
deleted file mode 100644
index 133f6302bde57..0000000000000
--- a/src/test/run-pass-fulldeps/issue-40663.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-#![allow(dead_code)]
-// aux-build:custom-derive-plugin.rs
-// ignore-stage1
-
-#![feature(plugin)]
-#![plugin(custom_derive_plugin)]
-
-#[derive_Nothing]
-#[derive_Nothing]
-#[derive_Nothing]
-struct S;
-
-fn main() {}

From cc17dbb37bd0d71aebb77691e60f7c43289b4cf5 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Thu, 6 Jun 2019 23:21:44 +0300
Subject: [PATCH 04/20] syntax: Use `MultiItemModifier` for built-in derives

---
 src/libsyntax/ext/base.rs                     |  7 +---
 src/libsyntax/ext/expand.rs                   | 40 +++++++++----------
 src/libsyntax_ext/deriving/bounds.rs          | 11 ++---
 src/libsyntax_ext/deriving/clone.rs           |  6 +--
 src/libsyntax_ext/deriving/cmp/eq.rs          |  6 +--
 src/libsyntax_ext/deriving/cmp/ord.rs         |  6 +--
 src/libsyntax_ext/deriving/cmp/partial_eq.rs  |  6 +--
 src/libsyntax_ext/deriving/cmp/partial_ord.rs |  6 +--
 src/libsyntax_ext/deriving/debug.rs           |  6 +--
 src/libsyntax_ext/deriving/decodable.rs       | 20 +++++-----
 src/libsyntax_ext/deriving/default.rs         |  6 +--
 src/libsyntax_ext/deriving/encodable.rs       | 20 +++++-----
 src/libsyntax_ext/deriving/generic/mod.rs     | 18 ++++-----
 src/libsyntax_ext/deriving/hash.rs            |  7 ++--
 src/libsyntax_ext/deriving/mod.rs             |  2 +-
 15 files changed, 82 insertions(+), 85 deletions(-)

diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 1a716c3faef1d..d45895c8d237e 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -1,6 +1,6 @@
 pub use SyntaxExtension::*;
 
-use crate::ast::{self, Attribute, Name, PatKind, MetaItem};
+use crate::ast::{self, Attribute, Name, PatKind};
 use crate::attr::HasAttrs;
 use crate::source_map::{SourceMap, Spanned, respan};
 use crate::edition::Edition;
@@ -516,9 +516,6 @@ impl MacResult for DummyResult {
     }
 }
 
-pub type BuiltinDeriveFn =
-    for<'cx> fn(&'cx mut ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable));
-
 /// Represents different kinds of macro invocations that can be resolved.
 #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum MacroKind {
@@ -604,7 +601,7 @@ pub enum SyntaxExtension {
                     Vec<Symbol> /* inert attribute names */, Edition),
 
     /// An attribute-like procedural macro that derives a builtin trait.
-    BuiltinDerive(BuiltinDeriveFn),
+    BuiltinDerive(Box<dyn MultiItemModifier + sync::Sync + sync::Send>),
 
     /// A declarative macro, e.g., `macro m() {}`.
     DeclMacro {
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 7d2928ef1807b..b314067fab664 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -893,29 +893,29 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             edition: ext.edition(self.cx.parse_sess.edition),
         };
 
-        match *ext {
-            ProcMacroDerive(ref ext, ..) => {
-                invoc.expansion_data.mark.set_expn_info(expn_info);
-                let span = span.with_ctxt(self.cx.backtrace());
-                let dummy = ast::MetaItem { // FIXME(jseyfried) avoid this
-                    path: Path::from_ident(Ident::invalid()),
-                    span: DUMMY_SP,
-                    node: ast::MetaItemKind::Word,
+        match ext {
+            ProcMacroDerive(expander, ..) | BuiltinDerive(expander) => {
+                let meta = match ext {
+                    ProcMacroDerive(..) => 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()?
+                    }
                 };
-                let items = ext.expand(self.cx, span, &dummy, item);
-                Some(invoc.fragment_kind.expect_from_annotatables(items))
-            }
-            BuiltinDerive(func) => {
-                expn_info.allow_internal_unstable = Some(vec![
-                    sym::rustc_attrs,
-                    Symbol::intern("derive_clone_copy"),
-                    Symbol::intern("derive_eq"),
-                    Symbol::intern("libstd_sys_internals"), // RustcDeserialize and RustcSerialize
-                ].into());
+
                 invoc.expansion_data.mark.set_expn_info(expn_info);
                 let span = span.with_ctxt(self.cx.backtrace());
-                let mut items = Vec::new();
-                func(self.cx, span, &attr.meta()?, &item, &mut |a| items.push(a));
+                let items = expander.expand(self.cx, span, &meta, item);
                 Some(invoc.fragment_kind.expect_from_annotatables(items))
             }
             _ => {
diff --git a/src/libsyntax_ext/deriving/bounds.rs b/src/libsyntax_ext/deriving/bounds.rs
index c7b805e0bdca6..ff700793a7b45 100644
--- a/src/libsyntax_ext/deriving/bounds.rs
+++ b/src/libsyntax_ext/deriving/bounds.rs
@@ -9,16 +9,17 @@ use syntax_pos::Span;
 pub fn expand_deriving_unsafe_bound(cx: &mut ExtCtxt<'_>,
                                     span: Span,
                                     _: &MetaItem,
-                                    _: &Annotatable,
-                                    _: &mut dyn FnMut(Annotatable)) {
+                                    _: Annotatable)
+                                    -> Vec<Annotatable> {
     cx.span_err(span, "this unsafe trait should be implemented explicitly");
+    Vec::new()
 }
 
 pub fn expand_deriving_copy(cx: &mut ExtCtxt<'_>,
                             span: Span,
                             mitem: &MetaItem,
-                            item: &Annotatable,
-                            push: &mut dyn FnMut(Annotatable)) {
+                            ref item: Annotatable)
+                            -> Vec<Annotatable> {
     let trait_def = TraitDef {
         span,
         attributes: Vec::new(),
@@ -31,5 +32,5 @@ pub fn expand_deriving_copy(cx: &mut ExtCtxt<'_>,
         associated_types: Vec::new(),
     };
 
-    trait_def.expand(cx, mitem, item, push);
+    trait_def.expand(cx, mitem, item)
 }
diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs
index b3b6328e2ca73..efd1333abbc66 100644
--- a/src/libsyntax_ext/deriving/clone.rs
+++ b/src/libsyntax_ext/deriving/clone.rs
@@ -13,8 +13,8 @@ use syntax_pos::Span;
 pub fn expand_deriving_clone(cx: &mut ExtCtxt<'_>,
                              span: Span,
                              mitem: &MetaItem,
-                             item: &Annotatable,
-                             push: &mut dyn FnMut(Annotatable)) {
+                             ref item: Annotatable)
+                             -> Vec<Annotatable> {
     // check if we can use a short form
     //
     // the short form is `fn clone(&self) -> Self { *self }`
@@ -100,7 +100,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt<'_>,
         associated_types: Vec::new(),
     };
 
-    trait_def.expand_ext(cx, mitem, item, push, is_shallow)
+    trait_def.expand_ext(cx, mitem, item, is_shallow)
 }
 
 fn cs_clone_shallow(name: &str,
diff --git a/src/libsyntax_ext/deriving/cmp/eq.rs b/src/libsyntax_ext/deriving/cmp/eq.rs
index 1d981e0ff7906..f16317d9ab59b 100644
--- a/src/libsyntax_ext/deriving/cmp/eq.rs
+++ b/src/libsyntax_ext/deriving/cmp/eq.rs
@@ -12,8 +12,8 @@ use syntax_pos::Span;
 pub fn expand_deriving_eq(cx: &mut ExtCtxt<'_>,
                           span: Span,
                           mitem: &MetaItem,
-                          item: &Annotatable,
-                          push: &mut dyn FnMut(Annotatable)) {
+                          ref item: Annotatable)
+                          -> Vec<Annotatable> {
     let inline = cx.meta_word(span, sym::inline);
     let hidden = cx.meta_list_item_word(span, sym::hidden);
     let doc = cx.meta_list(span, sym::doc, vec![hidden]);
@@ -41,7 +41,7 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt<'_>,
                       }],
         associated_types: Vec::new(),
     };
-    trait_def.expand_ext(cx, mitem, item, push, true)
+    trait_def.expand_ext(cx, mitem, item, true)
 }
 
 fn cs_total_eq_assert(cx: &mut ExtCtxt<'_>,
diff --git a/src/libsyntax_ext/deriving/cmp/ord.rs b/src/libsyntax_ext/deriving/cmp/ord.rs
index b25a9e4c50fbe..84bb02d49c4e6 100644
--- a/src/libsyntax_ext/deriving/cmp/ord.rs
+++ b/src/libsyntax_ext/deriving/cmp/ord.rs
@@ -12,8 +12,8 @@ use syntax_pos::Span;
 pub fn expand_deriving_ord(cx: &mut ExtCtxt<'_>,
                            span: Span,
                            mitem: &MetaItem,
-                           item: &Annotatable,
-                           push: &mut dyn FnMut(Annotatable)) {
+                           ref item: Annotatable)
+                           -> Vec<Annotatable> {
     let inline = cx.meta_word(span, sym::inline);
     let attrs = vec![cx.attribute(span, inline)];
     let trait_def = TraitDef {
@@ -40,7 +40,7 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt<'_>,
         associated_types: Vec::new(),
     };
 
-    trait_def.expand(cx, mitem, item, push)
+    trait_def.expand(cx, mitem, item)
 }
 
 
diff --git a/src/libsyntax_ext/deriving/cmp/partial_eq.rs b/src/libsyntax_ext/deriving/cmp/partial_eq.rs
index 6172f27261ecf..f56ee90ebad68 100644
--- a/src/libsyntax_ext/deriving/cmp/partial_eq.rs
+++ b/src/libsyntax_ext/deriving/cmp/partial_eq.rs
@@ -12,8 +12,8 @@ use syntax_pos::Span;
 pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt<'_>,
                                   span: Span,
                                   mitem: &MetaItem,
-                                  item: &Annotatable,
-                                  push: &mut dyn FnMut(Annotatable)) {
+                                  ref item: Annotatable)
+                                  -> Vec<Annotatable> {
     // structures are equal if all fields are equal, and non equal, if
     // any fields are not equal or if the enum variants are different
     fn cs_op(cx: &mut ExtCtxt<'_>,
@@ -99,5 +99,5 @@ pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt<'_>,
         methods,
         associated_types: Vec::new(),
     };
-    trait_def.expand(cx, mitem, item, push)
+    trait_def.expand(cx, mitem, item)
 }
diff --git a/src/libsyntax_ext/deriving/cmp/partial_ord.rs b/src/libsyntax_ext/deriving/cmp/partial_ord.rs
index 3980741f252dd..e02d1522c3955 100644
--- a/src/libsyntax_ext/deriving/cmp/partial_ord.rs
+++ b/src/libsyntax_ext/deriving/cmp/partial_ord.rs
@@ -14,8 +14,8 @@ use syntax_pos::Span;
 pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt<'_>,
                                    span: Span,
                                    mitem: &MetaItem,
-                                   item: &Annotatable,
-                                   push: &mut dyn FnMut(Annotatable)) {
+                                   ref item: Annotatable)
+                                   -> Vec<Annotatable> {
     macro_rules! md {
         ($name:expr, $op:expr, $equal:expr) => { {
             let inline = cx.meta_word(span, sym::inline);
@@ -83,7 +83,7 @@ pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt<'_>,
         methods,
         associated_types: Vec::new(),
     };
-    trait_def.expand(cx, mitem, item, push)
+    trait_def.expand(cx, mitem, item)
 }
 
 #[derive(Copy, Clone)]
diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs
index 44ddbb98809b4..ef2051cd03f18 100644
--- a/src/libsyntax_ext/deriving/debug.rs
+++ b/src/libsyntax_ext/deriving/debug.rs
@@ -15,8 +15,8 @@ use syntax_pos::{DUMMY_SP, Span};
 pub fn expand_deriving_debug(cx: &mut ExtCtxt<'_>,
                              span: Span,
                              mitem: &MetaItem,
-                             item: &Annotatable,
-                             push: &mut dyn FnMut(Annotatable)) {
+                             ref item: Annotatable)
+                             -> Vec<Annotatable> {
     // &mut ::std::fmt::Formatter
     let fmtr = Ptr(Box::new(Literal(path_std!(cx, fmt::Formatter))),
                    Borrowed(None, ast::Mutability::Mutable));
@@ -44,7 +44,7 @@ pub fn expand_deriving_debug(cx: &mut ExtCtxt<'_>,
                       }],
         associated_types: Vec::new(),
     };
-    trait_def.expand(cx, mitem, item, push)
+    trait_def.expand(cx, mitem, item)
 }
 
 /// We use the debug builders to do the heavy lifting here
diff --git a/src/libsyntax_ext/deriving/decodable.rs b/src/libsyntax_ext/deriving/decodable.rs
index d773f3ff7bcc5..90fc43783ab83 100644
--- a/src/libsyntax_ext/deriving/decodable.rs
+++ b/src/libsyntax_ext/deriving/decodable.rs
@@ -16,26 +16,26 @@ use syntax_pos::Span;
 pub fn expand_deriving_rustc_decodable(cx: &mut ExtCtxt<'_>,
                                        span: Span,
                                        mitem: &MetaItem,
-                                       item: &Annotatable,
-                                       push: &mut dyn FnMut(Annotatable)) {
-    expand_deriving_decodable_imp(cx, span, mitem, item, push, "rustc_serialize")
+                                       item: Annotatable)
+                                       -> Vec<Annotatable> {
+    expand_deriving_decodable_imp(cx, span, mitem, item, "rustc_serialize")
 }
 
 pub fn expand_deriving_decodable(cx: &mut ExtCtxt<'_>,
                                  span: Span,
                                  mitem: &MetaItem,
-                                 item: &Annotatable,
-                                 push: &mut dyn FnMut(Annotatable)) {
+                                 item: Annotatable)
+                                 -> Vec<Annotatable> {
     warn_if_deprecated(cx, span, "Decodable");
-    expand_deriving_decodable_imp(cx, span, mitem, item, push, "serialize")
+    expand_deriving_decodable_imp(cx, span, mitem, item, "serialize")
 }
 
 fn expand_deriving_decodable_imp(cx: &mut ExtCtxt<'_>,
                                  span: Span,
                                  mitem: &MetaItem,
-                                 item: &Annotatable,
-                                 push: &mut dyn FnMut(Annotatable),
-                                 krate: &'static str) {
+                                 ref item: Annotatable,
+                                 krate: &'static str)
+                                 -> Vec<Annotatable> {
     let typaram = &*deriving::hygienic_type_parameter(item, "__D");
 
     let trait_def = TraitDef {
@@ -76,7 +76,7 @@ fn expand_deriving_decodable_imp(cx: &mut ExtCtxt<'_>,
         associated_types: Vec::new(),
     };
 
-    trait_def.expand(cx, mitem, item, push)
+    trait_def.expand(cx, mitem, item)
 }
 
 fn decodable_substructure(cx: &mut ExtCtxt<'_>,
diff --git a/src/libsyntax_ext/deriving/default.rs b/src/libsyntax_ext/deriving/default.rs
index fd8e87e2fefd1..48bd753e7b16e 100644
--- a/src/libsyntax_ext/deriving/default.rs
+++ b/src/libsyntax_ext/deriving/default.rs
@@ -13,8 +13,8 @@ use syntax_pos::Span;
 pub fn expand_deriving_default(cx: &mut ExtCtxt<'_>,
                                span: Span,
                                mitem: &MetaItem,
-                               item: &Annotatable,
-                               push: &mut dyn FnMut(Annotatable)) {
+                               ref item: Annotatable)
+                               -> Vec<Annotatable> {
     let inline = cx.meta_word(span, sym::inline);
     let attrs = vec![cx.attribute(span, inline)];
     let trait_def = TraitDef {
@@ -40,7 +40,7 @@ pub fn expand_deriving_default(cx: &mut ExtCtxt<'_>,
                       }],
         associated_types: Vec::new(),
     };
-    trait_def.expand(cx, mitem, item, push)
+    trait_def.expand(cx, mitem, item)
 }
 
 fn default_substructure(cx: &mut ExtCtxt<'_>,
diff --git a/src/libsyntax_ext/deriving/encodable.rs b/src/libsyntax_ext/deriving/encodable.rs
index faaedba3e77dd..1893fb13460cb 100644
--- a/src/libsyntax_ext/deriving/encodable.rs
+++ b/src/libsyntax_ext/deriving/encodable.rs
@@ -97,26 +97,26 @@ use syntax_pos::Span;
 pub fn expand_deriving_rustc_encodable(cx: &mut ExtCtxt<'_>,
                                        span: Span,
                                        mitem: &MetaItem,
-                                       item: &Annotatable,
-                                       push: &mut dyn FnMut(Annotatable)) {
-    expand_deriving_encodable_imp(cx, span, mitem, item, push, "rustc_serialize")
+                                       item: Annotatable)
+                                       -> Vec<Annotatable> {
+    expand_deriving_encodable_imp(cx, span, mitem, item, "rustc_serialize")
 }
 
 pub fn expand_deriving_encodable(cx: &mut ExtCtxt<'_>,
                                  span: Span,
                                  mitem: &MetaItem,
-                                 item: &Annotatable,
-                                 push: &mut dyn FnMut(Annotatable)) {
+                                 item: Annotatable)
+                                 -> Vec<Annotatable> {
     warn_if_deprecated(cx, span, "Encodable");
-    expand_deriving_encodable_imp(cx, span, mitem, item, push, "serialize")
+    expand_deriving_encodable_imp(cx, span, mitem, item, "serialize")
 }
 
 fn expand_deriving_encodable_imp(cx: &mut ExtCtxt<'_>,
                                  span: Span,
                                  mitem: &MetaItem,
-                                 item: &Annotatable,
-                                 push: &mut dyn FnMut(Annotatable),
-                                 krate: &'static str) {
+                                 ref item: Annotatable,
+                                 krate: &'static str)
+                                 -> Vec<Annotatable> {
     let typaram = &*deriving::hygienic_type_parameter(item, "__S");
 
     let trait_def = TraitDef {
@@ -159,7 +159,7 @@ fn expand_deriving_encodable_imp(cx: &mut ExtCtxt<'_>,
         associated_types: Vec::new(),
     };
 
-    trait_def.expand(cx, mitem, item, push)
+    trait_def.expand(cx, mitem, item)
 }
 
 fn encodable_substructure(cx: &mut ExtCtxt<'_>,
diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs
index ffec667aba5d3..b97ee09eeb6ee 100644
--- a/src/libsyntax_ext/deriving/generic/mod.rs
+++ b/src/libsyntax_ext/deriving/generic/mod.rs
@@ -388,17 +388,17 @@ impl<'a> TraitDef<'a> {
     pub fn expand(self,
                   cx: &mut ExtCtxt<'_>,
                   mitem: &ast::MetaItem,
-                  item: &'a Annotatable,
-                  push: &mut dyn FnMut(Annotatable)) {
-        self.expand_ext(cx, mitem, item, push, false);
+                  item: &'a Annotatable)
+                  -> Vec<Annotatable> {
+        self.expand_ext(cx, mitem, item, false)
     }
 
     pub fn expand_ext(self,
                       cx: &mut ExtCtxt<'_>,
                       mitem: &ast::MetaItem,
                       item: &'a Annotatable,
-                      push: &mut dyn FnMut(Annotatable),
-                      from_scratch: bool) {
+                      from_scratch: bool)
+                      -> Vec<Annotatable> {
         match *item {
             Annotatable::Item(ref item) => {
                 let is_packed = item.attrs.iter().any(|attr| {
@@ -422,7 +422,7 @@ impl<'a> TraitDef<'a> {
                         // Non-ADT derive is an error, but it should have been
                         // set earlier; see
                         // libsyntax/ext/expand.rs:MacroExpander::expand()
-                        return;
+                        return Vec::new();
                     }
                 };
                 let is_always_copy =
@@ -453,7 +453,7 @@ impl<'a> TraitDef<'a> {
                         } else {
                             cx.span_err(mitem.span,
                                         "this trait cannot be derived for unions");
-                            return;
+                            return Vec::new();
                         }
                     }
                     _ => unreachable!(),
@@ -468,13 +468,13 @@ impl<'a> TraitDef<'a> {
                             .contains(&a.name_or_empty())
                     })
                     .cloned());
-                push(Annotatable::Item(P(ast::Item { attrs: attrs, ..(*newitem).clone() })))
+                vec![Annotatable::Item(P(ast::Item { attrs: attrs, ..(*newitem).clone() }))]
             }
             _ => {
                 // Non-Item derive is an error, but it should have been
                 // set earlier; see
                 // libsyntax/ext/expand.rs:MacroExpander::expand()
-                return;
+                Vec::new()
             }
         }
     }
diff --git a/src/libsyntax_ext/deriving/hash.rs b/src/libsyntax_ext/deriving/hash.rs
index e7f99d4578226..752bf774c8015 100644
--- a/src/libsyntax_ext/deriving/hash.rs
+++ b/src/libsyntax_ext/deriving/hash.rs
@@ -12,9 +12,8 @@ use syntax_pos::Span;
 pub fn expand_deriving_hash(cx: &mut ExtCtxt<'_>,
                             span: Span,
                             mitem: &MetaItem,
-                            item: &Annotatable,
-                            push: &mut dyn FnMut(Annotatable)) {
-
+                            ref item: Annotatable)
+                            -> Vec<Annotatable> {
     let path = Path::new_(pathvec_std!(cx, hash::Hash), None, vec![], PathKind::Std);
 
     let typaram = &*deriving::hygienic_type_parameter(item, "__H");
@@ -48,7 +47,7 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt<'_>,
         associated_types: Vec::new(),
     };
 
-    hash_trait_def.expand(cx, mitem, item, push);
+    hash_trait_def.expand(cx, mitem, item)
 }
 
 fn hash_substructure(cx: &mut ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'_>) -> P<Expr> {
diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs
index ac41f30e6b39f..d6d16d0dbd155 100644
--- a/src/libsyntax_ext/deriving/mod.rs
+++ b/src/libsyntax_ext/deriving/mod.rs
@@ -55,7 +55,7 @@ macro_rules! derive_traits {
             $(
                 resolver.add_builtin(
                     ast::Ident::with_empty_ctxt(Symbol::intern($name)),
-                    Lrc::new(SyntaxExtension::BuiltinDerive($func))
+                    Lrc::new(SyntaxExtension::BuiltinDerive(Box::new($func)))
                 );
             )*
         }

From fa48a02c0a743e0963d51162b1eb2dba5d4dd190 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Fri, 7 Jun 2019 00:37:47 +0300
Subject: [PATCH 05/20] Remove `SyntaxExtension::DeclMacro`

It's a less powerful duplicate of `SyntaxExtension::NormalTT`
---
 src/librustc_plugin/registry.rs               |  31 ++---
 src/librustc_resolve/macros.rs                |   3 +-
 .../passes/collect_intra_doc_links.rs         |   2 +-
 src/libsyntax/ext/base.rs                     |  18 +--
 src/libsyntax/ext/expand.rs                   |  11 +-
 src/libsyntax/ext/tt/macro_rules.rs           | 109 +++++++++---------
 src/libsyntax_ext/lib.rs                      |   4 +
 .../auxiliary/plugin-args.rs                  |   2 +
 .../ui/macros/nonterminal-matching.stderr     |   3 +
 9 files changed, 79 insertions(+), 104 deletions(-)

diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs
index 967fdcd2e7d41..f4b4bcb043c42 100644
--- a/src/librustc_plugin/registry.rs
+++ b/src/librustc_plugin/registry.rs
@@ -6,6 +6,7 @@ use rustc::util::nodemap::FxHashMap;
 
 use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT};
 use syntax::ext::base::MacroExpanderFn;
+use syntax::ext::hygiene::Transparency;
 use syntax::symbol::{Symbol, sym};
 use syntax::ast;
 use syntax::feature_gate::AttributeType;
@@ -84,33 +85,14 @@ impl<'a> Registry<'a> {
     /// Register a syntax extension of any kind.
     ///
     /// This is the most general hook into `libsyntax`'s expansion behavior.
-    pub fn register_syntax_extension(&mut self, name: ast::Name, extension: SyntaxExtension) {
+    pub fn register_syntax_extension(&mut self, name: ast::Name, mut extension: SyntaxExtension) {
         if name == sym::macro_rules {
             panic!("user-defined macros may not be named `macro_rules`");
         }
-        self.syntax_exts.push((name, match extension {
-            NormalTT {
-                expander,
-                def_info: _,
-                allow_internal_unstable,
-                allow_internal_unsafe,
-                local_inner_macros,
-                unstable_feature,
-                edition,
-            } => {
-                let nid = ast::CRATE_NODE_ID;
-                NormalTT {
-                    expander,
-                    def_info: Some((nid, self.krate_span)),
-                    allow_internal_unstable,
-                    allow_internal_unsafe,
-                    local_inner_macros,
-                    unstable_feature,
-                    edition,
-                }
-            }
-            _ => extension,
-        }));
+        if let NormalTT { def_info: ref mut def_info @ None, .. } = extension {
+            *def_info = Some((ast::CRATE_NODE_ID, self.krate_span));
+        }
+        self.syntax_exts.push((name, extension));
     }
 
     /// Register a macro of the usual kind.
@@ -122,6 +104,7 @@ impl<'a> Registry<'a> {
         self.register_syntax_extension(Symbol::intern(name), NormalTT {
             expander: Box::new(expander),
             def_info: None,
+            transparency: Transparency::SemiTransparent,
             allow_internal_unstable: None,
             allow_internal_unsafe: false,
             local_inner_macros: false,
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 08ab5b8532522..b5af7bb74a644 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -242,8 +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::NormalTT { def_info, .. } |
-                SyntaxExtension::DeclMacro { def_info, .. } => def_info,
+                SyntaxExtension::NormalTT { def_info, .. } => def_info,
                 _ => None,
             };
             if let Some((id, span)) = id_span {
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 860ea18a58ad0..1e824e6fdfba0 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -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::DeclMacro { .. } = *resolver.get_macro(res) {
+                if let SyntaxExtension::NormalTT { .. } = *resolver.get_macro(res) {
                     return Some(res.map_id(|_| panic!("unexpected id")));
                 }
             }
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index d45895c8d237e..bcee3e5a40bad 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -576,6 +576,7 @@ pub enum SyntaxExtension {
     NormalTT {
         expander: Box<dyn TTMacroExpander + sync::Sync + sync::Send>,
         def_info: Option<(ast::NodeId, Span)>,
+        transparency: Transparency,
         /// Whether the contents of the macro can
         /// directly use `#[unstable]` things.
         ///
@@ -602,21 +603,12 @@ pub enum SyntaxExtension {
 
     /// An attribute-like procedural macro that derives a builtin trait.
     BuiltinDerive(Box<dyn MultiItemModifier + sync::Sync + sync::Send>),
-
-    /// A declarative macro, e.g., `macro m() {}`.
-    DeclMacro {
-        expander: Box<dyn TTMacroExpander + sync::Sync + sync::Send>,
-        def_info: Option<(ast::NodeId, Span)>,
-        is_transparent: bool,
-        edition: Edition,
-    }
 }
 
 impl SyntaxExtension {
     /// Returns which kind of macro calls this syntax extension.
     pub fn kind(&self) -> MacroKind {
         match *self {
-            SyntaxExtension::DeclMacro { .. } |
             SyntaxExtension::NormalTT { .. } |
             SyntaxExtension::ProcMacro { .. } =>
                 MacroKind::Bang,
@@ -632,19 +624,19 @@ impl SyntaxExtension {
 
     pub fn default_transparency(&self) -> Transparency {
         match *self {
+            SyntaxExtension::NormalTT { transparency, .. } => transparency,
             SyntaxExtension::ProcMacro { .. } |
             SyntaxExtension::AttrProcMacro(..) |
             SyntaxExtension::ProcMacroDerive(..) |
-            SyntaxExtension::DeclMacro { is_transparent: false, .. } => Transparency::Opaque,
-            SyntaxExtension::DeclMacro { is_transparent: true, .. } => Transparency::Transparent,
-            _ => Transparency::SemiTransparent,
+            SyntaxExtension::NonMacroAttr { .. } => Transparency::Opaque,
+            SyntaxExtension::MultiModifier(..) |
+            SyntaxExtension::BuiltinDerive(..) => Transparency::SemiTransparent,
         }
     }
 
     pub fn edition(&self, default_edition: Edition) -> Edition {
         match *self {
             SyntaxExtension::NormalTT { edition, .. } |
-            SyntaxExtension::DeclMacro { edition, .. } |
             SyntaxExtension::ProcMacro { edition, .. } |
             SyntaxExtension::AttrProcMacro(.., edition) |
             SyntaxExtension::ProcMacroDerive(.., edition) => edition,
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index b314067fab664..8b49b9b028441 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -747,16 +747,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         };
 
         let opt_expanded = match *ext {
-            DeclMacro { ref expander, def_info, edition, .. } => {
-                if let Err(dummy_span) = validate_and_set_expn_info(self, def_info.map(|(_, s)| s),
-                                                                    None, false, false, None,
-                                                                    edition) {
-                    dummy_span
-                } else {
-                    kind.make_from(expander.expand(self.cx, span, mac.node.stream(), None))
-                }
-            }
-
             NormalTT {
                 ref expander,
                 def_info,
@@ -765,6 +755,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 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(),
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index 285c88357a6a8..8c4072db27b17 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -3,6 +3,7 @@ use crate::edition::Edition;
 use crate::ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension};
 use crate::ext::base::{NormalTT, TTMacroExpander};
 use crate::ext::expand::{AstFragment, AstFragmentKind};
+use crate::ext::hygiene::Transparency;
 use crate::ext::tt::macro_parser::{Success, Error, Failure};
 use crate::ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal};
 use crate::ext::tt::macro_parser::{parse, parse_failure_msg};
@@ -375,65 +376,65 @@ pub fn compile(
         valid,
     });
 
-    if body.legacy {
-        let allow_internal_unstable = attr::find_by_name(&def.attrs, sym::allow_internal_unstable)
-            .map(|attr| attr
-                .meta_item_list()
-                .map(|list| list.iter()
-                    .filter_map(|it| {
-                        let name = it.ident().map(|ident| ident.name);
-                        if name.is_none() {
-                            sess.span_diagnostic.span_err(it.span(),
-                                "allow internal unstable expects feature names")
-                        }
-                        name
-                    })
-                    .collect::<Vec<Symbol>>().into()
-                )
-                .unwrap_or_else(|| {
-                    sess.span_diagnostic.span_warn(
-                        attr.span, "allow_internal_unstable expects list of feature names. In the \
-                        future this will become a hard error. Please use `allow_internal_unstable(\
-                        foo, bar)` to only allow the `foo` and `bar` features",
-                    );
-                    vec![sym::allow_internal_unstable_backcompat_hack].into()
+    let transparency = if attr::contains_name(&def.attrs, sym::rustc_transparent_macro) {
+        Transparency::Transparent
+    } else if body.legacy {
+        Transparency::SemiTransparent
+    } else {
+        Transparency::Opaque
+    };
+
+    let allow_internal_unstable = attr::find_by_name(&def.attrs, sym::allow_internal_unstable)
+        .map(|attr| attr
+            .meta_item_list()
+            .map(|list| list.iter()
+                .filter_map(|it| {
+                    let name = it.ident().map(|ident| ident.name);
+                    if name.is_none() {
+                        sess.span_diagnostic.span_err(it.span(),
+                            "allow internal unstable expects feature names")
+                    }
+                    name
                 })
-            );
-        let allow_internal_unsafe = attr::contains_name(&def.attrs, sym::allow_internal_unsafe);
-        let mut local_inner_macros = false;
-        if let Some(macro_export) = attr::find_by_name(&def.attrs, sym::macro_export) {
-            if let Some(l) = macro_export.meta_item_list() {
-                local_inner_macros = attr::list_contains_name(&l, sym::local_inner_macros);
-            }
-        }
+                .collect::<Vec<Symbol>>().into()
+            )
+            .unwrap_or_else(|| {
+                sess.span_diagnostic.span_warn(
+                    attr.span, "allow_internal_unstable expects list of feature names. In the \
+                    future this will become a hard error. Please use `allow_internal_unstable(\
+                    foo, bar)` to only allow the `foo` and `bar` features",
+                );
+                vec![sym::allow_internal_unstable_backcompat_hack].into()
+            })
+        );
 
-        let unstable_feature = attr::find_stability(&sess,
-                                                    &def.attrs, def.span).and_then(|stability| {
-            if let attr::StabilityLevel::Unstable { issue, .. } = stability.level {
-                Some((stability.feature, issue))
-            } else {
-                None
-            }
-        });
-
-        NormalTT {
-            expander,
-            def_info: Some((def.id, def.span)),
-            allow_internal_unstable,
-            allow_internal_unsafe,
-            local_inner_macros,
-            unstable_feature,
-            edition,
+    let allow_internal_unsafe = attr::contains_name(&def.attrs, sym::allow_internal_unsafe);
+
+    let mut local_inner_macros = false;
+    if let Some(macro_export) = attr::find_by_name(&def.attrs, sym::macro_export) {
+        if let Some(l) = macro_export.meta_item_list() {
+            local_inner_macros = attr::list_contains_name(&l, sym::local_inner_macros);
         }
-    } else {
-        let is_transparent = attr::contains_name(&def.attrs, sym::rustc_transparent_macro);
+    }
 
-        SyntaxExtension::DeclMacro {
-            expander,
-            def_info: Some((def.id, def.span)),
-            is_transparent,
-            edition,
+    let unstable_feature = attr::find_stability(&sess,
+                                                &def.attrs, def.span).and_then(|stability| {
+        if let attr::StabilityLevel::Unstable { issue, .. } = stability.level {
+            Some((stability.feature, issue))
+        } else {
+            None
         }
+    });
+
+    NormalTT {
+        expander,
+        def_info: Some((def.id, def.span)),
+        transparency,
+        allow_internal_unstable,
+        allow_internal_unsafe,
+        local_inner_macros,
+        unstable_feature,
+        edition,
     }
 }
 
diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs
index fc00154427501..7d6abd14a4a00 100644
--- a/src/libsyntax_ext/lib.rs
+++ b/src/libsyntax_ext/lib.rs
@@ -42,6 +42,7 @@ pub mod proc_macro_impl;
 use rustc_data_structures::sync::Lrc;
 use syntax::ast;
 use syntax::ext::base::{MacroExpanderFn, NormalTT, NamedSyntaxExtension, MultiModifier};
+use syntax::ext::hygiene::Transparency;
 use syntax::edition::Edition;
 use syntax::symbol::{sym, Symbol};
 
@@ -59,6 +60,7 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver,
                      NormalTT {
                         expander: Box::new($f as MacroExpanderFn),
                         def_info: None,
+                        transparency: Transparency::SemiTransparent,
                         allow_internal_unstable: None,
                         allow_internal_unsafe: false,
                         local_inner_macros: false,
@@ -102,6 +104,7 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver,
              NormalTT {
                 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,
@@ -112,6 +115,7 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver,
              NormalTT {
                  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,
diff --git a/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs b/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs
index 096701bd9b3ed..cf12b80848436 100644
--- a/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs
@@ -13,6 +13,7 @@ use syntax::ast;
 use syntax::ext::hygiene;
 use syntax::ext::build::AstBuilder;
 use syntax::ext::base::{TTMacroExpander, ExtCtxt, MacResult, MacEager, NormalTT};
+use syntax::ext::hygiene::Transparency;
 use syntax::print::pprust;
 use syntax::ptr::P;
 use syntax::symbol::Symbol;
@@ -43,6 +44,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
         NormalTT {
             expander: Box::new(Expander { args: args, }),
             def_info: None,
+            transparency: Transparency::SemiTransparent,
             allow_internal_unstable: None,
             allow_internal_unsafe: false,
             local_inner_macros: false,
diff --git a/src/test/ui/macros/nonterminal-matching.stderr b/src/test/ui/macros/nonterminal-matching.stderr
index 5fba8002e1c48..93cc97d45830b 100644
--- a/src/test/ui/macros/nonterminal-matching.stderr
+++ b/src/test/ui/macros/nonterminal-matching.stderr
@@ -1,6 +1,9 @@
 error: no rules expected the token `enum E { }`
   --> $DIR/nonterminal-matching.rs:19:10
    |
+LL |     macro n(a $nt_item b) {
+   |     --------------------- when calling this macro
+...
 LL |     n!(a $nt_item b);
    |          ^^^^^^^^ no rules expected this token in macro call
 ...

From a9397fd0d5eede4bbc0ada94bf92657ca8084cb3 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Fri, 7 Jun 2019 01:59:27 +0300
Subject: [PATCH 06/20] syntax: Improve documentation of `SyntaxExtension`

---
 src/libsyntax/ext/base.rs | 90 +++++++++++++++++++++++----------------
 1 file changed, 54 insertions(+), 36 deletions(-)

diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index bcee3e5a40bad..4e5971a075f10 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -549,60 +549,78 @@ impl MacroKind {
 
 /// An enum representing the different kinds of syntax extensions.
 pub enum SyntaxExtension {
-    /// A trivial "extension" that does nothing, only keeps the attribute and marks it as known.
-    NonMacroAttr { mark_used: bool },
-
-    /// A syntax extension that is attached to an item and modifies it
-    /// in-place. Also allows decoration, i.e., creating new items.
-    MultiModifier(Box<dyn MultiItemModifier + sync::Sync + sync::Send>),
-
-    /// A function-like procedural macro. TokenStream -> TokenStream.
+    /// A token-based function-like macro.
     ProcMacro {
+        /// 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
+        /// 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,
     },
 
-    /// An attribute-like procedural macro. TokenStream, TokenStream -> TokenStream.
-    /// The first TokenSteam is the attribute, the second is the annotated item.
-    /// Allows modification of the input items and adding new items, similar to
-    /// MultiModifier, but uses TokenStreams, rather than AST nodes.
-    AttrProcMacro(Box<dyn AttrProcMacro + sync::Sync + sync::Send>, Edition),
-
-    /// A normal, function-like syntax extension.
-    ///
-    /// `bytes!` is a `NormalTT`.
+    /// An AST-based function-like macro.
     NormalTT {
+        /// 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,
-        /// Whether the contents of the macro can
-        /// directly use `#[unstable]` things.
-        ///
-        /// Only allows things that require a feature gate in the given whitelist
+        /// Whitelist of unstable features that are treated as stable inside this macro.
         allow_internal_unstable: Option<Lrc<[Symbol]>>,
-        /// Whether the contents of the macro can use `unsafe`
-        /// without triggering the `unsafe_code` lint.
+        /// Suppresses the `unsafe_code` lint for code produced by this macro.
         allow_internal_unsafe: bool,
-        /// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`)
-        /// for a given macro.
+        /// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro.
         local_inner_macros: bool,
-        /// The macro's feature name if it is unstable, and the stability feature
+        /// The macro's feature name and tracking issue number if it is unstable.
         unstable_feature: Option<(Symbol, u32)>,
-        /// Edition of the crate in which the macro is defined
+        /// Edition of the crate in which this macro is defined.
         edition: Edition,
     },
 
-    /// An attribute-like procedural macro. TokenStream -> TokenStream.
-    /// The input is the annotated item.
-    /// Allows generating code to implement a Trait for a given struct
-    /// or enum item.
-    ProcMacroDerive(Box<dyn MultiItemModifier + sync::Sync + sync::Send>,
-                    Vec<Symbol> /* inert attribute names */, Edition),
+    /// A token-based attribute macro.
+    AttrProcMacro(
+        /// An expander with signature (TokenStream, TokenStream) -> TokenStream.
+        /// 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.
+    MultiModifier(
+        /// An expander with signature (AST, AST) -> AST.
+        /// The first AST fragment is the attribute itself, the second is the annotated item.
+        /// The produced AST fragment replaces the input AST fragment.
+        Box<dyn MultiItemModifier + sync::Sync + sync::Send>,
+    ),
+
+    /// A trivial attribute "macro" that does nothing,
+    /// only keeps the attribute and marks it as known.
+    NonMacroAttr {
+        /// Suppresses the `unused_attributes` lint for this attribute.
+        mark_used: bool,
+    },
 
-    /// An attribute-like procedural macro that derives a builtin trait.
-    BuiltinDerive(Box<dyn MultiItemModifier + sync::Sync + sync::Send>),
+    /// A token-based derive macro.
+    ProcMacroDerive(
+        /// 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.
+    BuiltinDerive(
+        /// An expander with signature AST -> AST.
+        /// The produced AST fragment is appended to the input AST fragment.
+        Box<dyn MultiItemModifier + sync::Sync + sync::Send>,
+    ),
 }
 
 impl SyntaxExtension {

From 48d2c0bfd48cd29a15605e6c733ccad3414b0eb2 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Fri, 7 Jun 2019 02:30:01 +0300
Subject: [PATCH 07/20] syntax: Rename variants of `SyntaxExtension` for
 consistency

---
 src/librustc_metadata/creader.rs              |  6 +-
 src/librustc_metadata/cstore_impl.rs          |  2 +-
 src/librustc_plugin/registry.rs               |  8 +--
 src/librustc_resolve/macros.rs                |  4 +-
 src/librustdoc/clean/inline.rs                |  2 +-
 .../passes/collect_intra_doc_links.rs         |  2 +-
 src/libsyntax/ext/base.rs                     | 55 +++++++++----------
 src/libsyntax/ext/expand.rs                   | 26 +++++----
 src/libsyntax/ext/tt/macro_rules.rs           |  5 +-
 src/libsyntax_ext/deriving/mod.rs             |  2 +-
 src/libsyntax_ext/lib.rs                      | 15 ++---
 .../auxiliary/plugin-args.rs                  |  8 +--
 12 files changed, 65 insertions(+), 70 deletions(-)

diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 991bebc647d0f..7ffba41e2569a 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -614,7 +614,7 @@ impl<'a> CrateLoader<'a> {
             match decl {
                 ProcMacro::CustomDerive { trait_name, attributes, client } => {
                     let attrs = attributes.iter().cloned().map(Symbol::intern).collect::<Vec<_>>();
-                    (trait_name, SyntaxExtension::ProcMacroDerive(
+                    (trait_name, SyntaxExtension::Derive(
                         Box::new(ProcMacroDerive {
                             client,
                             attrs: attrs.clone(),
@@ -624,13 +624,13 @@ impl<'a> CrateLoader<'a> {
                     ))
                 }
                 ProcMacro::Attr { name, client } => {
-                    (name, SyntaxExtension::AttrProcMacro(
+                    (name, SyntaxExtension::Attr(
                         Box::new(AttrProcMacro { client }),
                         root.edition,
                     ))
                 }
                 ProcMacro::Bang { name, client } => {
-                    (name, SyntaxExtension::ProcMacro {
+                    (name, SyntaxExtension::Bang {
                         expander: Box::new(BangProcMacro { client }),
                         allow_internal_unstable: None,
                         edition: root.edition,
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index db452bb4ac7bc..35faa1df82b84 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -430,7 +430,7 @@ impl cstore::CStore {
             use syntax_ext::proc_macro_impl::BangProcMacro;
 
             let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote);
-            let ext = SyntaxExtension::ProcMacro {
+            let ext = SyntaxExtension::Bang {
                 expander: Box::new(BangProcMacro { client }),
                 allow_internal_unstable: Some(vec![sym::proc_macro_def_site].into()),
                 edition: data.root.edition,
diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs
index f4b4bcb043c42..dd5e42684c427 100644
--- a/src/librustc_plugin/registry.rs
+++ b/src/librustc_plugin/registry.rs
@@ -4,7 +4,7 @@ use rustc::lint::{EarlyLintPassObject, LateLintPassObject, LintId, Lint};
 use rustc::session::Session;
 use rustc::util::nodemap::FxHashMap;
 
-use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT};
+use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension};
 use syntax::ext::base::MacroExpanderFn;
 use syntax::ext::hygiene::Transparency;
 use syntax::symbol::{Symbol, sym};
@@ -89,7 +89,7 @@ impl<'a> Registry<'a> {
         if name == sym::macro_rules {
             panic!("user-defined macros may not be named `macro_rules`");
         }
-        if let NormalTT { def_info: ref mut def_info @ None, .. } = extension {
+        if let SyntaxExtension::LegacyBang { def_info: ref mut def_info @ None, .. } = extension {
             *def_info = Some((ast::CRATE_NODE_ID, self.krate_span));
         }
         self.syntax_exts.push((name, extension));
@@ -98,10 +98,10 @@ 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 `NormalTT` that calls `expander`,
+    /// It builds for you a `SyntaxExtension::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), NormalTT {
+        self.register_syntax_extension(Symbol::intern(name), SyntaxExtension::LegacyBang {
             expander: Box::new(expander),
             def_info: None,
             transparency: Transparency::SemiTransparent,
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index b5af7bb74a644..2369bddf4f75f 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -242,7 +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::NormalTT { def_info, .. } => def_info,
+                SyntaxExtension::LegacyBang { def_info, .. } => def_info,
                 _ => None,
             };
             if let Some((id, span)) = id_span {
@@ -586,7 +586,7 @@ impl<'a> Resolver<'a> {
                         match self.resolve_macro_to_res(derive, MacroKind::Derive,
                                                         &parent_scope, true, force) {
                             Ok((_, ext)) => {
-                                if let SyntaxExtension::ProcMacroDerive(_, helpers, _) = &*ext {
+                                if let SyntaxExtension::Derive(_, helpers, _) = &*ext {
                                     if helpers.contains(&ident.name) {
                                         let binding =
                                             (Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 15108a7dbb91c..5a5540e7e3855 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -471,7 +471,7 @@ fn build_macro(cx: &DocContext<'_>, did: DefId, name: ast::Name) -> clean::ItemE
         }
         LoadedMacro::ProcMacro(ext) => {
             let helpers = match &*ext {
-                &SyntaxExtension::ProcMacroDerive(_, ref syms, ..) => { syms.clean(cx) }
+                &SyntaxExtension::Derive(_, ref syms, ..) => { syms.clean(cx) }
                 _ => Vec::new(),
             };
 
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 1e824e6fdfba0..7fbfc3e1fc0f4 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -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::NormalTT { .. } = *resolver.get_macro(res) {
+                if let SyntaxExtension::LegacyBang { .. } = *resolver.get_macro(res) {
                     return Some(res.map_id(|_| panic!("unexpected id")));
                 }
             }
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 4e5971a075f10..045e45071d1c6 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -1,5 +1,3 @@
-pub use SyntaxExtension::*;
-
 use crate::ast::{self, Attribute, Name, PatKind};
 use crate::attr::HasAttrs;
 use crate::source_map::{SourceMap, Spanned, respan};
@@ -550,7 +548,7 @@ impl MacroKind {
 /// An enum representing the different kinds of syntax extensions.
 pub enum SyntaxExtension {
     /// A token-based function-like macro.
-    ProcMacro {
+    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.
@@ -560,7 +558,7 @@ pub enum SyntaxExtension {
     },
 
     /// An AST-based function-like macro.
-    NormalTT {
+    LegacyBang {
         /// An expander with signature TokenStream -> AST.
         expander: Box<dyn TTMacroExpander + sync::Sync + sync::Send>,
         /// Some info about the macro's definition point.
@@ -580,7 +578,7 @@ pub enum SyntaxExtension {
     },
 
     /// A token-based attribute macro.
-    AttrProcMacro(
+    Attr(
         /// An expander with signature (TokenStream, TokenStream) -> TokenStream.
         /// The first TokenSteam is the attribute itself, the second is the annotated item.
         /// The produced TokenSteam replaces the input TokenSteam.
@@ -590,7 +588,7 @@ pub enum SyntaxExtension {
     ),
 
     /// An AST-based attribute macro.
-    MultiModifier(
+    LegacyAttr(
         /// An expander with signature (AST, AST) -> AST.
         /// The first AST fragment is the attribute itself, the second is the annotated item.
         /// The produced AST fragment replaces the input AST fragment.
@@ -605,7 +603,7 @@ pub enum SyntaxExtension {
     },
 
     /// A token-based derive macro.
-    ProcMacroDerive(
+    Derive(
         /// An expander with signature TokenStream -> TokenStream (not yet).
         /// The produced TokenSteam is appended to the input TokenSteam.
         Box<dyn MultiItemModifier + sync::Sync + sync::Send>,
@@ -616,7 +614,7 @@ pub enum SyntaxExtension {
     ),
 
     /// An AST-based derive macro.
-    BuiltinDerive(
+    LegacyDerive(
         /// An expander with signature AST -> AST.
         /// The produced AST fragment is appended to the input AST fragment.
         Box<dyn MultiItemModifier + sync::Sync + sync::Send>,
@@ -627,41 +625,38 @@ impl SyntaxExtension {
     /// Returns which kind of macro calls this syntax extension.
     pub fn kind(&self) -> MacroKind {
         match *self {
-            SyntaxExtension::NormalTT { .. } |
-            SyntaxExtension::ProcMacro { .. } =>
-                MacroKind::Bang,
-            SyntaxExtension::NonMacroAttr { .. } |
-            SyntaxExtension::MultiModifier(..) |
-            SyntaxExtension::AttrProcMacro(..) =>
-                MacroKind::Attr,
-            SyntaxExtension::ProcMacroDerive(..) |
-            SyntaxExtension::BuiltinDerive(..) =>
-                MacroKind::Derive,
+            SyntaxExtension::Bang { .. } |
+            SyntaxExtension::LegacyBang { .. } => MacroKind::Bang,
+            SyntaxExtension::Attr(..) |
+            SyntaxExtension::LegacyAttr(..) |
+            SyntaxExtension::NonMacroAttr { .. } => MacroKind::Attr,
+            SyntaxExtension::Derive(..) |
+            SyntaxExtension::LegacyDerive(..) => MacroKind::Derive,
         }
     }
 
     pub fn default_transparency(&self) -> Transparency {
         match *self {
-            SyntaxExtension::NormalTT { transparency, .. } => transparency,
-            SyntaxExtension::ProcMacro { .. } |
-            SyntaxExtension::AttrProcMacro(..) |
-            SyntaxExtension::ProcMacroDerive(..) |
+            SyntaxExtension::LegacyBang { transparency, .. } => transparency,
+            SyntaxExtension::Bang { .. } |
+            SyntaxExtension::Attr(..) |
+            SyntaxExtension::Derive(..) |
             SyntaxExtension::NonMacroAttr { .. } => Transparency::Opaque,
-            SyntaxExtension::MultiModifier(..) |
-            SyntaxExtension::BuiltinDerive(..) => Transparency::SemiTransparent,
+            SyntaxExtension::LegacyAttr(..) |
+            SyntaxExtension::LegacyDerive(..) => Transparency::SemiTransparent,
         }
     }
 
     pub fn edition(&self, default_edition: Edition) -> Edition {
         match *self {
-            SyntaxExtension::NormalTT { edition, .. } |
-            SyntaxExtension::ProcMacro { edition, .. } |
-            SyntaxExtension::AttrProcMacro(.., edition) |
-            SyntaxExtension::ProcMacroDerive(.., edition) => edition,
+            SyntaxExtension::Bang { edition, .. } |
+            SyntaxExtension::LegacyBang { edition, .. } |
+            SyntaxExtension::Attr(.., edition) |
+            SyntaxExtension::Derive(.., edition) => edition,
             // Unstable legacy stuff
             SyntaxExtension::NonMacroAttr { .. } |
-            SyntaxExtension::MultiModifier(..) |
-            SyntaxExtension::BuiltinDerive(..) => default_edition,
+            SyntaxExtension::LegacyAttr(..) |
+            SyntaxExtension::LegacyDerive(..) => default_edition,
         }
     }
 }
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 8b49b9b028441..cdb2348f8afe4 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -389,7 +389,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                         let item = match self.cx.resolver.resolve_macro_path(
                                 path, MacroKind::Derive, Mark::root(), Vec::new(), false) {
                             Ok(ext) => match *ext {
-                                BuiltinDerive(..) => item_with_markers.clone(),
+                                SyntaxExtension::LegacyDerive(..) => item_with_markers.clone(),
                                 _ => item.clone(),
                             },
                             _ => item.clone(),
@@ -548,7 +548,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             _ => unreachable!(),
         };
 
-        if let NonMacroAttr { mark_used: false } = *ext {} else {
+        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);
@@ -564,18 +564,18 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         });
 
         match *ext {
-            NonMacroAttr { .. } => {
+            SyntaxExtension::NonMacroAttr { .. } => {
                 attr::mark_known(&attr);
                 item.visit_attrs(|attrs| attrs.push(attr));
                 Some(invoc.fragment_kind.expect_from_annotatables(iter::once(item)))
             }
-            MultiModifier(ref mac) => {
+            SyntaxExtension::LegacyAttr(ref mac) => {
                 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);
                 Some(invoc.fragment_kind.expect_from_annotatables(item))
             }
-            AttrProcMacro(ref mac, ..) => {
+            SyntaxExtension::Attr(ref mac, ..) => {
                 self.gate_proc_macro_attr_item(attr.span, &item);
                 let item_tok = TokenTree::Token(DUMMY_SP, Token::Interpolated(Lrc::new(match item {
                     Annotatable::Item(item) => token::NtItem(item),
@@ -592,7 +592,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 self.gate_proc_macro_expansion(attr.span, &res);
                 res
             }
-            ProcMacroDerive(..) | BuiltinDerive(..) => {
+            SyntaxExtension::Derive(..) | SyntaxExtension::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)
@@ -747,7 +747,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         };
 
         let opt_expanded = match *ext {
-            NormalTT {
+            SyntaxExtension::LegacyBang {
                 ref expander,
                 def_info,
                 ref allow_internal_unstable,
@@ -774,20 +774,22 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 }
             }
 
-            MultiModifier(..) | AttrProcMacro(..) | SyntaxExtension::NonMacroAttr { .. } => {
+            SyntaxExtension::Attr(..) |
+            SyntaxExtension::LegacyAttr(..) |
+            SyntaxExtension::NonMacroAttr { .. } => {
                 self.cx.span_err(path.span,
                                  &format!("`{}` can only be used in attributes", path));
                 self.cx.trace_macros_diag();
                 kind.dummy(span)
             }
 
-            ProcMacroDerive(..) | BuiltinDerive(..) => {
+            SyntaxExtension::Derive(..) | SyntaxExtension::LegacyDerive(..) => {
                 self.cx.span_err(path.span, &format!("`{}` is a derive macro", path));
                 self.cx.trace_macros_diag();
                 kind.dummy(span)
             }
 
-            SyntaxExtension::ProcMacro { ref expander, ref allow_internal_unstable, edition } => {
+            SyntaxExtension::Bang { ref expander, ref allow_internal_unstable, edition } => {
                 if ident.name != kw::Invalid {
                     let msg =
                         format!("macro {}! expects no ident argument, given '{}'", path, ident);
@@ -885,9 +887,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         };
 
         match ext {
-            ProcMacroDerive(expander, ..) | BuiltinDerive(expander) => {
+            SyntaxExtension::Derive(expander, ..) | SyntaxExtension::LegacyDerive(expander) => {
                 let meta = match ext {
-                    ProcMacroDerive(..) => ast::MetaItem { // FIXME(jseyfried) avoid this
+                    SyntaxExtension::Derive(..) => ast::MetaItem { // FIXME(jseyfried) avoid this
                         path: Path::from_ident(Ident::invalid()),
                         span: DUMMY_SP,
                         node: ast::MetaItemKind::Word,
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index 8c4072db27b17..f262ab3e5fc93 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -1,7 +1,6 @@
 use crate::{ast, attr};
 use crate::edition::Edition;
-use crate::ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension};
-use crate::ext::base::{NormalTT, TTMacroExpander};
+use crate::ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension, TTMacroExpander};
 use crate::ext::expand::{AstFragment, AstFragmentKind};
 use crate::ext::hygiene::Transparency;
 use crate::ext::tt::macro_parser::{Success, Error, Failure};
@@ -426,7 +425,7 @@ pub fn compile(
         }
     });
 
-    NormalTT {
+    SyntaxExtension::LegacyBang {
         expander,
         def_info: Some((def.id, def.span)),
         transparency,
diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs
index d6d16d0dbd155..7a8e624cb9894 100644
--- a/src/libsyntax_ext/deriving/mod.rs
+++ b/src/libsyntax_ext/deriving/mod.rs
@@ -55,7 +55,7 @@ macro_rules! derive_traits {
             $(
                 resolver.add_builtin(
                     ast::Ident::with_empty_ctxt(Symbol::intern($name)),
-                    Lrc::new(SyntaxExtension::BuiltinDerive(Box::new($func)))
+                    Lrc::new(SyntaxExtension::LegacyDerive(Box::new($func)))
                 );
             )*
         }
diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs
index 7d6abd14a4a00..7c4085aa09653 100644
--- a/src/libsyntax_ext/lib.rs
+++ b/src/libsyntax_ext/lib.rs
@@ -41,7 +41,8 @@ pub mod proc_macro_impl;
 
 use rustc_data_structures::sync::Lrc;
 use syntax::ast;
-use syntax::ext::base::{MacroExpanderFn, NormalTT, NamedSyntaxExtension, MultiModifier};
+
+use syntax::ext::base::{MacroExpanderFn, NamedSyntaxExtension, SyntaxExtension};
 use syntax::ext::hygiene::Transparency;
 use syntax::edition::Edition;
 use syntax::symbol::{sym, Symbol};
@@ -57,7 +58,7 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver,
     macro_rules! register {
         ($( $name:ident: $f:expr, )*) => { $(
             register(Symbol::intern(stringify!($name)),
-                     NormalTT {
+                     SyntaxExtension::LegacyBang {
                         expander: Box::new($f as MacroExpanderFn),
                         def_info: None,
                         transparency: Transparency::SemiTransparent,
@@ -95,13 +96,13 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver,
         assert: assert::expand_assert,
     }
 
-    register(sym::test_case, MultiModifier(Box::new(test_case::expand)));
-    register(sym::test, MultiModifier(Box::new(test::expand_test)));
-    register(sym::bench, MultiModifier(Box::new(test::expand_bench)));
+    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)));
 
     // format_args uses `unstable` things internally.
     register(Symbol::intern("format_args"),
-             NormalTT {
+             SyntaxExtension::LegacyBang {
                 expander: Box::new(format::expand_format_args),
                 def_info: None,
                 transparency: Transparency::SemiTransparent,
@@ -112,7 +113,7 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver,
                 edition,
             });
     register(sym::format_args_nl,
-             NormalTT {
+             SyntaxExtension::LegacyBang {
                  expander: Box::new(format::expand_format_args_nl),
                  def_info: None,
                  transparency: Transparency::SemiTransparent,
diff --git a/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs b/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs
index cf12b80848436..330459fc08f55 100644
--- a/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs
@@ -10,12 +10,10 @@ extern crate rustc_plugin;
 
 use std::borrow::ToOwned;
 use syntax::ast;
-use syntax::ext::hygiene;
 use syntax::ext::build::AstBuilder;
-use syntax::ext::base::{TTMacroExpander, ExtCtxt, MacResult, MacEager, NormalTT};
+use syntax::ext::base::{SyntaxExtension, TTMacroExpander, ExtCtxt, MacResult, MacEager};
 use syntax::ext::hygiene::Transparency;
 use syntax::print::pprust;
-use syntax::ptr::P;
 use syntax::symbol::Symbol;
 use syntax_pos::Span;
 use syntax::tokenstream::TokenStream;
@@ -30,7 +28,7 @@ impl TTMacroExpander for Expander {
                    ecx: &'cx mut ExtCtxt,
                    sp: Span,
                    _: TokenStream,
-                   _: Option<Span>) -> Box<MacResult+'cx> {
+                   _: Option<Span>) -> Box<dyn MacResult+'cx> {
         let args = self.args.iter().map(|i| pprust::meta_list_item_to_string(i))
             .collect::<Vec<_>>().join(", ");
         MacEager::expr(ecx.expr_str(sp, Symbol::intern(&args)))
@@ -41,7 +39,7 @@ impl TTMacroExpander for Expander {
 pub fn plugin_registrar(reg: &mut Registry) {
     let args = reg.args().to_owned();
     reg.register_syntax_extension(Symbol::intern("plugin_args"),
-        NormalTT {
+        SyntaxExtension::LegacyBang {
             expander: Box::new(Expander { args: args, }),
             def_info: None,
             transparency: Transparency::SemiTransparent,

From f1867c549754403ac305be8f22a9e93642b3e288 Mon Sep 17 00:00:00 2001
From: varkor <github@varkor.com>
Date: Fri, 7 Jun 2019 10:18:03 +0100
Subject: [PATCH 08/20] Rename `infer_types` to `infer_args`

---
 src/librustc/hir/lowering.rs     |  4 ++--
 src/librustc/hir/mod.rs          |  8 ++++----
 src/librustc/hir/print.rs        | 16 ++++++++--------
 src/librustc_typeck/astconv.rs   | 30 +++++++++++++++---------------
 src/librustc_typeck/check/mod.rs |  8 ++++----
 5 files changed, 33 insertions(+), 33 deletions(-)

diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index d6ad335525c14..1b433c8da60b0 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -2168,7 +2168,7 @@ impl<'a> LoweringContext<'a> {
         itctx: ImplTraitContext<'_>,
         explicit_owner: Option<NodeId>,
     ) -> hir::PathSegment {
-        let (mut generic_args, infer_types) = if let Some(ref generic_args) = segment.args {
+        let (mut generic_args, infer_args) = if let Some(ref generic_args) = segment.args {
             let msg = "parenthesized type parameters may only be used with a `Fn` trait";
             match **generic_args {
                 GenericArgs::AngleBracketed(ref data) => {
@@ -2305,7 +2305,7 @@ impl<'a> LoweringContext<'a> {
             Some(id),
             Some(self.lower_res(res)),
             generic_args,
-            infer_types,
+            infer_args,
         )
     }
 
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 2aaf5ec775d49..82b7dfd363f14 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -348,7 +348,7 @@ pub struct PathSegment {
     /// This only applies to expression and pattern paths, and
     /// out of those only the segments with no type parameters
     /// to begin with, e.g., `Vec::new` is `<Vec<..>>::new::<..>`.
-    pub infer_types: bool,
+    pub infer_args: bool,
 }
 
 impl PathSegment {
@@ -358,7 +358,7 @@ impl PathSegment {
             ident,
             hir_id: None,
             res: None,
-            infer_types: true,
+            infer_args: true,
             args: None,
         }
     }
@@ -368,13 +368,13 @@ impl PathSegment {
         hir_id: Option<HirId>,
         res: Option<Res>,
         args: GenericArgs,
-        infer_types: bool,
+        infer_args: bool,
     ) -> Self {
         PathSegment {
             ident,
             hir_id,
             res,
-            infer_types,
+            infer_args,
             args: if args.is_empty() {
                 None
             } else {
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index c8615f0ed1b93..7b0a499fa5c66 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -1196,7 +1196,7 @@ impl<'a> State<'a> {
 
         segment.with_generic_args(|generic_args| {
             if !generic_args.args.is_empty() || !generic_args.bindings.is_empty() {
-                return self.print_generic_args(&generic_args, segment.infer_types, true);
+                return self.print_generic_args(&generic_args, segment.infer_args, true);
             }
             Ok(())
         })?;
@@ -1561,7 +1561,7 @@ impl<'a> State<'a> {
             if segment.ident.name != kw::PathRoot {
                self.print_ident(segment.ident)?;
                segment.with_generic_args(|generic_args| {
-                   self.print_generic_args(generic_args, segment.infer_types,
+                   self.print_generic_args(generic_args, segment.infer_args,
                                            colons_before_params)
                })?;
             }
@@ -1574,7 +1574,7 @@ impl<'a> State<'a> {
         if segment.ident.name != kw::PathRoot {
            self.print_ident(segment.ident)?;
            segment.with_generic_args(|generic_args| {
-               self.print_generic_args(generic_args, segment.infer_types, false)
+               self.print_generic_args(generic_args, segment.infer_args, false)
            })?;
         }
         Ok(())
@@ -1602,7 +1602,7 @@ impl<'a> State<'a> {
                         self.print_ident(segment.ident)?;
                         segment.with_generic_args(|generic_args| {
                             self.print_generic_args(generic_args,
-                                                    segment.infer_types,
+                                                    segment.infer_args,
                                                     colons_before_params)
                         })?;
                     }
@@ -1614,7 +1614,7 @@ impl<'a> State<'a> {
                 self.print_ident(item_segment.ident)?;
                 item_segment.with_generic_args(|generic_args| {
                     self.print_generic_args(generic_args,
-                                            item_segment.infer_types,
+                                            item_segment.infer_args,
                                             colons_before_params)
                 })
             }
@@ -1626,7 +1626,7 @@ impl<'a> State<'a> {
                 self.print_ident(item_segment.ident)?;
                 item_segment.with_generic_args(|generic_args| {
                     self.print_generic_args(generic_args,
-                                            item_segment.infer_types,
+                                            item_segment.infer_args,
                                             colons_before_params)
                 })
             }
@@ -1635,7 +1635,7 @@ impl<'a> State<'a> {
 
     fn print_generic_args(&mut self,
                              generic_args: &hir::GenericArgs,
-                             infer_types: bool,
+                             infer_args: bool,
                              colons_before_params: bool)
                              -> io::Result<()> {
         if generic_args.parenthesized {
@@ -1681,7 +1681,7 @@ impl<'a> State<'a> {
 
             // FIXME(eddyb): this would leak into error messages (e.g.,
             // "non-exhaustive patterns: `Some::<..>(_)` not covered").
-            if infer_types && false {
+            if infer_args && false {
                 start_or_comma(self)?;
                 self.s.word("..")?;
             }
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 34f817ba570e7..bac4df927b66a 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -191,7 +191,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                 span,
                 def_id,
                 generic_args,
-                item_segment.infer_types,
+                item_segment.infer_args,
                 None,
             )
         });
@@ -208,7 +208,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
         seg: &hir::PathSegment,
         generics: &ty::Generics,
     ) -> bool {
-        let explicit = !seg.infer_types;
+        let explicit = !seg.infer_args;
         let impl_trait = generics.params.iter().any(|param| match param.kind {
             ty::GenericParamDefKind::Type {
                 synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), ..
@@ -259,7 +259,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                 GenericArgPosition::Value
             },
             def.parent.is_none() && def.has_self, // `has_self`
-            seg.infer_types || suppress_mismatch, // `infer_types`
+            seg.infer_args || suppress_mismatch, // `infer_args`
         ).0
     }
 
@@ -272,7 +272,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
         args: &hir::GenericArgs,
         position: GenericArgPosition,
         has_self: bool,
-        infer_types: bool,
+        infer_args: bool,
     ) -> (bool, Option<Vec<Span>>) {
         // At this stage we are guaranteed that the generic arguments are in the correct order, e.g.
         // that lifetimes will proceed types. So it suffices to check the number of each generic
@@ -414,7 +414,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
             );
         }
         // Note that type errors are currently be emitted *after* const errors.
-        if !infer_types
+        if !infer_args
             || arg_counts.types > param_counts.types - defaults.types - has_self as usize {
             check_kind_count(
                 "type",
@@ -511,7 +511,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
             }
 
             // Check whether this segment takes generic arguments and the user has provided any.
-            let (generic_args, infer_types) = args_for_def_id(def_id);
+            let (generic_args, infer_args) = args_for_def_id(def_id);
 
             let mut args = generic_args.iter().flat_map(|generic_args| generic_args.args.iter())
                 .peekable();
@@ -535,7 +535,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                             | (GenericArg::Const(_), GenericParamDefKind::Lifetime) => {
                                 // We expected a lifetime argument, but got a type or const
                                 // argument. That means we're inferring the lifetimes.
-                                substs.push(inferred_kind(None, param, infer_types));
+                                substs.push(inferred_kind(None, param, infer_args));
                                 params.next();
                             }
                             (_, _) => {
@@ -556,7 +556,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                     (None, Some(&param)) => {
                         // If there are fewer arguments than parameters, it means
                         // we're inferring the remaining arguments.
-                        substs.push(inferred_kind(Some(&substs), param, infer_types));
+                        substs.push(inferred_kind(Some(&substs), param, infer_args));
                         args.next();
                         params.next();
                     }
@@ -592,7 +592,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
         span: Span,
         def_id: DefId,
         generic_args: &'a hir::GenericArgs,
-        infer_types: bool,
+        infer_args: bool,
         self_ty: Option<Ty<'tcx>>)
         -> (SubstsRef<'tcx>, Vec<ConvertedBinding<'tcx>>, Option<Vec<Span>>)
     {
@@ -617,7 +617,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
             &generic_args,
             GenericArgPosition::Type,
             has_self,
-            infer_types,
+            infer_args,
         );
 
         let is_object = self_ty.map_or(false, |ty| {
@@ -644,7 +644,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
             self_ty.is_some(),
             self_ty,
             // Provide the generic args, and whether types should be inferred.
-            |_| (Some(generic_args), infer_types),
+            |_| (Some(generic_args), infer_args),
             // Provide substitutions for parameters for which (valid) arguments have been provided.
             |param, arg| {
                 match (&param.kind, arg) {
@@ -661,11 +661,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                 }
             },
             // Provide substitutions for parameters for which arguments are inferred.
-            |substs, param, infer_types| {
+            |substs, param, infer_args| {
                 match param.kind {
                     GenericParamDefKind::Lifetime => tcx.lifetimes.re_static.into(),
                     GenericParamDefKind::Type { has_default, .. } => {
-                        if !infer_types && has_default {
+                        if !infer_args && has_default {
                             // No type parameter provided, but a default exists.
 
                             // If we are converting an object type, then the
@@ -693,7 +693,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                                        .subst_spanned(tcx, substs.unwrap(), Some(span))
                                 ).into()
                             }
-                        } else if infer_types {
+                        } else if infer_args {
                             // No type parameters were provided, we can infer all.
                             if !default_needs_object_self(param) {
                                 self.ty_infer_for_def(param, span).into()
@@ -880,7 +880,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
             self.create_substs_for_ast_path(span,
                                             trait_def_id,
                                             generic_args,
-                                            trait_segment.infer_types,
+                                            trait_segment.infer_args,
                                             Some(self_ty))
         })
     }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index a111851aa3797..c66d5ff08c0b8 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -5419,10 +5419,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     if !infer_args_for_err.contains(&index) {
                         // Check whether the user has provided generic arguments.
                         if let Some(ref data) = segments[index].args {
-                            return (Some(data), segments[index].infer_types);
+                            return (Some(data), segments[index].infer_args);
                         }
                     }
-                    return (None, segments[index].infer_types);
+                    return (None, segments[index].infer_args);
                 }
 
                 (None, true)
@@ -5443,13 +5443,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
             },
             // Provide substitutions for parameters for which arguments are inferred.
-            |substs, param, infer_types| {
+            |substs, param, infer_args| {
                 match param.kind {
                     GenericParamDefKind::Lifetime => {
                         self.re_infer(span, Some(param)).unwrap().into()
                     }
                     GenericParamDefKind::Type { has_default, .. } => {
-                        if !infer_types && has_default {
+                        if !infer_args && has_default {
                             // If we have a default, then we it doesn't matter that we're not
                             // inferring the type arguments: we provide the default where any
                             // is missing.

From 5377dea7fc8dc1f05ddc4c444fddf1994293bfeb Mon Sep 17 00:00:00 2001
From: varkor <github@varkor.com>
Date: Thu, 6 Jun 2019 01:55:09 +0100
Subject: [PATCH 09/20] Fix issue with const arg inference

---
 src/librustc_typeck/astconv.rs     | 24 ++++++++++++++++++------
 src/librustc_typeck/check/mod.rs   | 19 ++++++++++++++++++-
 src/librustc_typeck/collect.rs     | 20 ++++++++++++++++++--
 src/librustc_typeck/error_codes.rs |  4 ++--
 4 files changed, 56 insertions(+), 11 deletions(-)

diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index bac4df927b66a..349c4e608c244 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -13,7 +13,7 @@ use crate::middle::resolve_lifetime as rl;
 use crate::namespace::Namespace;
 use rustc::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
 use rustc::traits;
-use rustc::ty::{self, DefIdTree, Ty, TyCtxt, ToPredicate, TypeFoldable};
+use rustc::ty::{self, DefIdTree, Ty, TyCtxt, Const, ToPredicate, TypeFoldable};
 use rustc::ty::{GenericParamDef, GenericParamDefKind};
 use rustc::ty::subst::{Kind, Subst, InternalSubsts, SubstsRef};
 use rustc::ty::wf::object_region_bounds;
@@ -61,6 +61,13 @@ pub trait AstConv<'gcx, 'tcx> {
                         span: Span) -> Ty<'tcx> {
         self.ty_infer(span)
     }
+    /// What const should we use when a const is omitted?
+    fn ct_infer(
+        &self,
+        ty: Ty<'tcx>,
+        param: Option<&ty::GenericParamDef>,
+        span: Span,
+    ) -> &'tcx Const<'tcx>;
 
     /// Projecting an associated type from a (potentially)
     /// higher-ranked trait reference is more complicated, because of
@@ -280,7 +287,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
         let param_counts = def.own_counts();
         let arg_counts = args.own_counts();
         let infer_lifetimes = position != GenericArgPosition::Type && arg_counts.lifetimes == 0;
-        let infer_consts = position != GenericArgPosition::Type && arg_counts.consts == 0;
 
         let mut defaults: ty::GenericParamCount = Default::default();
         for param in &def.params {
@@ -333,7 +339,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                 offset
             );
             // We enforce the following: `required` <= `provided` <= `permitted`.
-            // For kinds without defaults (i.e., lifetimes), `required == permitted`.
+            // For kinds without defaults (e.g.., lifetimes), `required == permitted`.
             // For other kinds (i.e., types), `permitted` may be greater than `required`.
             if required <= provided && provided <= permitted {
                 return (reported_late_bound_region_err.unwrap_or(false), None);
@@ -404,7 +410,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
             );
         }
         // FIXME(const_generics:defaults)
-        if !infer_consts || arg_counts.consts > param_counts.consts {
+        if !infer_args || arg_counts.consts > param_counts.consts {
             check_kind_count(
                 "const",
                 param_counts.consts,
@@ -707,8 +713,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                     }
                     GenericParamDefKind::Const => {
                         // FIXME(const_generics:defaults)
-                        // We've already errored above about the mismatch.
-                        tcx.consts.err.into()
+                        if infer_args {
+                            // No const parameters were provided, we can infer all.
+                            let ty = tcx.at(span).type_of(param.def_id);
+                            self.ct_infer(ty, Some(param), span).into()
+                        } else {
+                            // We've already errored above about the mismatch.
+                            tcx.consts.err.into()
+                        }
                     }
                 }
             },
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index c66d5ff08c0b8..acb0b73af886d 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -100,11 +100,12 @@ use rustc_data_structures::indexed_vec::Idx;
 use rustc_target::spec::abi::Abi;
 use rustc::infer::opaque_types::OpaqueTypeDecl;
 use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
 use rustc::middle::region;
 use rustc::mir::interpret::{ConstValue, GlobalId};
 use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
 use rustc::ty::{
-    self, AdtKind, CanonicalUserType, Ty, TyCtxt, GenericParamDefKind, Visibility,
+    self, AdtKind, CanonicalUserType, Ty, TyCtxt, Const, GenericParamDefKind, Visibility,
     ToPolyTraitRef, ToPredicate, RegionKind, UserType
 };
 use rustc::ty::adjustment::{
@@ -1959,6 +1960,22 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
                         span: Span) -> Ty<'tcx> {
         if let UnpackedKind::Type(ty) = self.var_for_def(span, ty_param_def).unpack() {
             return ty;
+    fn ct_infer(
+        &self,
+        ty: Ty<'tcx>,
+        param: Option<&ty::GenericParamDef>,
+        span: Span,
+    ) -> &'tcx Const<'tcx> {
+        if let Some(param) = param {
+            if let UnpackedKind::Const(ct) = self.var_for_def(span, param).unpack() {
+                return ct;
+            }
+            unreachable!()
+        } else {
+            self.next_const_var(ty, ConstVariableOrigin {
+                kind: ConstVariableOriginKind::ConstInference,
+                span,
+            })
         }
         unreachable!()
     }
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 2751cd0a37ec0..64b92687cfe17 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -26,7 +26,7 @@ use rustc::ty::subst::{Subst, InternalSubsts};
 use rustc::ty::util::Discr;
 use rustc::ty::util::IntTypeExt;
 use rustc::ty::subst::UnpackedKind;
-use rustc::ty::{self, AdtKind, DefIdTree, ToPolyTraitRef, Ty, TyCtxt};
+use rustc::ty::{self, AdtKind, DefIdTree, ToPolyTraitRef, Ty, TyCtxt, Const};
 use rustc::ty::{ReprOptions, ToPredicate};
 use rustc::util::captures::Captures;
 use rustc::util::nodemap::FxHashMap;
@@ -47,7 +47,7 @@ use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc::hir::GenericParamKind;
 use rustc::hir::{self, CodegenFnAttrFlags, CodegenFnAttrs, Unsafety};
 
-use errors::Applicability;
+use errors::{Applicability, DiagnosticId};
 
 use std::iter;
 
@@ -204,6 +204,22 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
         self.tcx().types.err
     }
 
+    fn ct_infer(
+        &self,
+        _: Ty<'tcx>,
+        _: Option<&ty::GenericParamDef>,
+        span: Span,
+    ) -> &'tcx Const<'tcx> {
+        self.tcx().sess.struct_span_err_with_code(
+            span,
+            "the const placeholder `_` is not allowed within types on item signatures",
+            DiagnosticId::Error("E0121".into()),
+        ).span_label(span, "not allowed in type signatures")
+         .emit();
+
+        self.tcx().consts.err
+    }
+
     fn projected_ty_from_poly_trait_ref(
         &self,
         span: Span,
diff --git a/src/librustc_typeck/error_codes.rs b/src/librustc_typeck/error_codes.rs
index b5a50f4387581..66e9a6e6b2a2e 100644
--- a/src/librustc_typeck/error_codes.rs
+++ b/src/librustc_typeck/error_codes.rs
@@ -1482,8 +1482,8 @@ impl <'a> Drop for MyWrapper<'a> {
 "##,
 
 E0121: r##"
-In order to be consistent with Rust's lack of global type inference, type
-placeholders are disallowed by design in item signatures.
+In order to be consistent with Rust's lack of global type inference,
+type and const placeholders are disallowed by design in item signatures.
 
 Examples of this error include:
 

From a0e3e9ab9d50c74e51a81d566c941dfee6733ce5 Mon Sep 17 00:00:00 2001
From: varkor <github@varkor.com>
Date: Thu, 6 Jun 2019 01:55:34 +0100
Subject: [PATCH 10/20] Refactor `ty_infer` and `re_infer`

---
 src/librustc_typeck/astconv.rs       | 31 +++++++++++++--------------
 src/librustc_typeck/check/closure.rs |  2 +-
 src/librustc_typeck/check/mod.rs     | 32 ++++++++++++++++------------
 src/librustc_typeck/collect.rs       | 13 ++++++-----
 4 files changed, 40 insertions(+), 38 deletions(-)

diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 349c4e608c244..63d9f0920cc7b 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -49,19 +49,17 @@ pub trait AstConv<'gcx, 'tcx> {
                                  -> &'tcx ty::GenericPredicates<'tcx>;
 
     /// Returns the lifetime to use when a lifetime is omitted (and not elided).
-    fn re_infer(&self, span: Span, _def: Option<&ty::GenericParamDef>)
+    fn re_infer(
+        &self,
+        param: Option<&ty::GenericParamDef>,
+        span: Span,
+    )
                 -> Option<ty::Region<'tcx>>;
 
     /// Returns the type to use when a type is omitted.
-    fn ty_infer(&self, span: Span) -> Ty<'tcx>;
+    fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx>;
 
-    /// Same as `ty_infer`, but with a known type parameter definition.
-    fn ty_infer_for_def(&self,
-                        _def: &ty::GenericParamDef,
-                        span: Span) -> Ty<'tcx> {
-        self.ty_infer(span)
-    }
-    /// What const should we use when a const is omitted?
+    /// Returns the const to use when a const is omitted.
     fn ct_infer(
         &self,
         ty: Ty<'tcx>,
@@ -163,7 +161,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
             }
 
             None => {
-                self.re_infer(lifetime.span, def)
+                self.re_infer(def, lifetime.span)
                     .unwrap_or_else(|| {
                         // This indicates an illegal lifetime
                         // elision. `resolve_lifetime` should have
@@ -701,11 +699,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                             }
                         } else if infer_args {
                             // No type parameters were provided, we can infer all.
-                            if !default_needs_object_self(param) {
-                                self.ty_infer_for_def(param, span).into()
+                            let param = if !default_needs_object_self(param) {
+                                Some(param)
                             } else {
-                                self.ty_infer(span).into()
-                            }
+                                None
+                            };
+                            self.ty_infer(param, span).into()
                         } else {
                             // We've already errored above about the mismatch.
                             tcx.types.err.into()
@@ -1440,7 +1439,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                 if tcx.named_region(lifetime.hir_id).is_some() {
                     self.ast_region_to_region(lifetime, None)
                 } else {
-                    self.re_infer(span, None).unwrap_or_else(|| {
+                    self.re_infer(None, span).unwrap_or_else(|| {
                         span_err!(tcx.sess, span, E0228,
                             "the lifetime bound for this object type cannot be deduced \
                              from context; please supply an explicit bound");
@@ -2134,7 +2133,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                 // values in a ExprKind::Closure, or as
                 // the type of local variables. Both of these cases are
                 // handled specially and will not descend into this routine.
-                self.ty_infer(ast_ty.span)
+                self.ty_infer(None, ast_ty.span)
             }
             hir::TyKind::CVarArgs(lt) => {
                 let va_list_did = match tcx.lang_items().va_list() {
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 4427a83562e9e..b894fc8c83c10 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -598,7 +598,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let supplied_arguments = decl.inputs.iter().map(|a| astconv.ast_ty_to_ty(a));
         let supplied_return = match decl.output {
             hir::Return(ref output) => astconv.ast_ty_to_ty(&output),
-            hir::DefaultReturn(_) => astconv.ty_infer(decl.output.span()),
+            hir::DefaultReturn(_) => astconv.ty_infer(None, decl.output.span()),
         };
 
         let result = ty::Binder::bind(self.tcx.mk_fn_sig(
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index acb0b73af886d..0b558a20ed47e 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1939,8 +1939,11 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
         })
     }
 
-    fn re_infer(&self, span: Span, def: Option<&ty::GenericParamDef>)
-                -> Option<ty::Region<'tcx>> {
+    fn re_infer(
+        &self,
+        def: Option<&ty::GenericParamDef>,
+        span: Span,
+    ) -> Option<ty::Region<'tcx>> {
         let v = match def {
             Some(def) => infer::EarlyBoundRegion(span, def.name),
             None => infer::MiscVariable(span)
@@ -1948,18 +1951,20 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
         Some(self.next_region_var(v))
     }
 
-    fn ty_infer(&self, span: Span) -> Ty<'tcx> {
-        self.next_ty_var(TypeVariableOrigin {
-            kind: TypeVariableOriginKind::TypeInference,
-            span,
-        })
+    fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
+        if let Some(param) = param {
+            if let UnpackedKind::Type(ty) = self.var_for_def(span, param).unpack() {
+                return ty;
+            }
+            unreachable!()
+        } else {
+            self.next_ty_var(TypeVariableOrigin {
+                kind: TypeVariableOriginKind::TypeInference,
+                span,
+            })
+        }
     }
 
-    fn ty_infer_for_def(&self,
-                        ty_param_def: &ty::GenericParamDef,
-                        span: Span) -> Ty<'tcx> {
-        if let UnpackedKind::Type(ty) = self.var_for_def(span, ty_param_def).unpack() {
-            return ty;
     fn ct_infer(
         &self,
         ty: Ty<'tcx>,
@@ -1977,7 +1982,6 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
                 span,
             })
         }
-        unreachable!()
     }
 
     fn projected_ty_from_poly_trait_ref(&self,
@@ -5463,7 +5467,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             |substs, param, infer_args| {
                 match param.kind {
                     GenericParamDefKind::Lifetime => {
-                        self.re_infer(span, Some(param)).unwrap().into()
+                        self.re_infer(Some(param), span).unwrap().into()
                     }
                     GenericParamDefKind::Type { has_default, .. } => {
                         if !infer_args && has_default {
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 64b92687cfe17..8b770096cad09 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -186,18 +186,17 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
 
     fn re_infer(
         &self,
-        _span: Span,
-        _def: Option<&ty::GenericParamDef>,
+        _: Option<&ty::GenericParamDef>,
+        _: Span,
     ) -> Option<ty::Region<'tcx>> {
         None
     }
 
-    fn ty_infer(&self, span: Span) -> Ty<'tcx> {
-        struct_span_err!(
-            self.tcx().sess,
+    fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
+        self.tcx().sess.struct_span_err_with_code(
             span,
-            E0121,
-            "the type placeholder `_` is not allowed within types on item signatures"
+            "the type placeholder `_` is not allowed within types on item signatures",
+            DiagnosticId::Error("E0121".into()),
         ).span_label(span, "not allowed in type signatures")
          .emit();
 

From 647b4a4deb8de06cdc375187ecaf29ebeaa65f98 Mon Sep 17 00:00:00 2001
From: varkor <github@varkor.com>
Date: Thu, 6 Jun 2019 01:55:57 +0100
Subject: [PATCH 11/20] Add test for const generics struct constructor

---
 .../const-generics/array-wrapper-struct-ctor.rs   | 15 +++++++++++++++
 .../array-wrapper-struct-ctor.stderr              |  6 ++++++
 2 files changed, 21 insertions(+)
 create mode 100644 src/test/ui/const-generics/array-wrapper-struct-ctor.rs
 create mode 100644 src/test/ui/const-generics/array-wrapper-struct-ctor.stderr

diff --git a/src/test/ui/const-generics/array-wrapper-struct-ctor.rs b/src/test/ui/const-generics/array-wrapper-struct-ctor.rs
new file mode 100644
index 0000000000000..d83846fcf88d4
--- /dev/null
+++ b/src/test/ui/const-generics/array-wrapper-struct-ctor.rs
@@ -0,0 +1,15 @@
+// run-pass
+
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+struct ArrayStruct<T, const N: usize> {
+    data: [T; N],
+}
+
+struct ArrayTuple<T, const N: usize>([T; N]);
+
+fn main() {
+    let _ = ArrayStruct { data: [0u32; 8] };
+    let _ = ArrayTuple([0u32; 8]);
+}
diff --git a/src/test/ui/const-generics/array-wrapper-struct-ctor.stderr b/src/test/ui/const-generics/array-wrapper-struct-ctor.stderr
new file mode 100644
index 0000000000000..bd18264c1637d
--- /dev/null
+++ b/src/test/ui/const-generics/array-wrapper-struct-ctor.stderr
@@ -0,0 +1,6 @@
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+  --> $DIR/array-wrapper-struct-ctor.rs:3:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+

From 7bb0a16ad701c1cd22c0b2c05afd55f06a532062 Mon Sep 17 00:00:00 2001
From: varkor <github@varkor.com>
Date: Thu, 6 Jun 2019 01:56:09 +0100
Subject: [PATCH 12/20] Add test for deriving Debug for const generics

---
 .../derive-debug-array-wrapper.rs             |  9 +++++++++
 .../derive-debug-array-wrapper.stderr         | 19 +++++++++++++++++++
 2 files changed, 28 insertions(+)
 create mode 100644 src/test/ui/const-generics/derive-debug-array-wrapper.rs
 create mode 100644 src/test/ui/const-generics/derive-debug-array-wrapper.stderr

diff --git a/src/test/ui/const-generics/derive-debug-array-wrapper.rs b/src/test/ui/const-generics/derive-debug-array-wrapper.rs
new file mode 100644
index 0000000000000..a29cb90ebb79a
--- /dev/null
+++ b/src/test/ui/const-generics/derive-debug-array-wrapper.rs
@@ -0,0 +1,9 @@
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+#[derive(Debug)]
+struct X<const N: usize> {
+    a: [u32; N], //~ ERROR `[u32; _]` doesn't implement `std::fmt::Debug`
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/derive-debug-array-wrapper.stderr b/src/test/ui/const-generics/derive-debug-array-wrapper.stderr
new file mode 100644
index 0000000000000..5bab1d1b54a3e
--- /dev/null
+++ b/src/test/ui/const-generics/derive-debug-array-wrapper.stderr
@@ -0,0 +1,19 @@
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+  --> $DIR/derive-debug-array-wrapper.rs:1:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+
+error[E0277]: `[u32; _]` doesn't implement `std::fmt::Debug`
+  --> $DIR/derive-debug-array-wrapper.rs:6:5
+   |
+LL |     a: [u32; N],
+   |     ^^^^^^^^^^^ `[u32; _]` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
+   |
+   = help: the trait `std::fmt::Debug` is not implemented for `[u32; _]`
+   = note: required because of the requirements on the impl of `std::fmt::Debug` for `&[u32; _]`
+   = note: required for the cast to the object type `dyn std::fmt::Debug`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.

From f11e6f7fa7d0a8ff1e73ff28b26667ee0a1acd87 Mon Sep 17 00:00:00 2001
From: varkor <github@varkor.com>
Date: Fri, 7 Jun 2019 00:21:16 +0100
Subject: [PATCH 13/20] Fix issue with path segment lowering with const args

---
 src/librustc/hir/lowering.rs | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 1b433c8da60b0..81ea96c0eb732 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -2230,9 +2230,9 @@ impl<'a> LoweringContext<'a> {
                 .collect();
             if expected_lifetimes > 0 && param_mode == ParamMode::Explicit {
                 let anon_lt_suggestion = vec!["'_"; expected_lifetimes].join(", ");
-                let no_ty_args = generic_args.args.len() == expected_lifetimes;
+                let no_non_lt_args = generic_args.args.len() == expected_lifetimes;
                 let no_bindings = generic_args.bindings.is_empty();
-                let (incl_angl_brckt, insertion_span, suggestion) = if no_ty_args && no_bindings {
+                let (incl_angl_brckt, insertion_sp, suggestion) = if no_non_lt_args && no_bindings {
                     // If there are no (non-implicit) generic args or associated type
                     // bindings, our suggestion includes the angle brackets.
                     (true, path_span.shrink_to_hi(), format!("<{}>", anon_lt_suggestion))
@@ -2240,7 +2240,7 @@ impl<'a> LoweringContext<'a> {
                     // Otherwise (sorry, this is kind of gross) we need to infer the
                     // place to splice in the `'_, ` from the generics that do exist.
                     let first_generic_span = first_generic_span
-                        .expect("already checked that type args or bindings exist");
+                        .expect("already checked that non-lifetime args or bindings exist");
                     (false, first_generic_span.shrink_to_lo(), format!("{}, ", anon_lt_suggestion))
                 };
                 match self.anonymous_lifetime_mode {
@@ -2263,7 +2263,7 @@ impl<'a> LoweringContext<'a> {
                             expected_lifetimes,
                             path_span,
                             incl_angl_brckt,
-                            insertion_span,
+                            insertion_sp,
                             suggestion,
                         );
                         err.emit();
@@ -2280,7 +2280,7 @@ impl<'a> LoweringContext<'a> {
                                 expected_lifetimes,
                                 path_span,
                                 incl_angl_brckt,
-                                insertion_span,
+                                insertion_sp,
                                 suggestion,
                             )
                         );
@@ -2316,9 +2316,10 @@ impl<'a> LoweringContext<'a> {
         mut itctx: ImplTraitContext<'_>,
     ) -> (hir::GenericArgs, bool) {
         let &AngleBracketedArgs { ref args, ref constraints, .. } = data;
-        let has_types = args.iter().any(|arg| match arg {
+        let has_non_lt_args = args.iter().any(|arg| match arg {
+            ast::GenericArg::Lifetime(_) => false,
             ast::GenericArg::Type(_) => true,
-            _ => false,
+            ast::GenericArg::Const(_) => true,
         });
         (
             hir::GenericArgs {
@@ -2328,7 +2329,7 @@ impl<'a> LoweringContext<'a> {
                     .collect(),
                 parenthesized: false,
             },
-            !has_types && param_mode == ParamMode::Optional
+            !has_non_lt_args && param_mode == ParamMode::Optional
         )
     }
 

From 00f8f82a23dcd569ad203396f6e3e15c228fc444 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Mon, 3 Jun 2019 17:34:41 +0200
Subject: [PATCH 14/20] some more comments for const_qualif

---
 src/librustc_mir/transform/qualify_consts.rs | 43 +++++++++++++-------
 1 file changed, 28 insertions(+), 15 deletions(-)

diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 64aecee633719..7b2c8af5e35e2 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -135,6 +135,12 @@ enum ValueSource<'a, 'tcx> {
     },
 }
 
+/// A "qualif" is a way to lookg for something "bad" in the MIR that would prevent
+/// proper const evaluation.  So `return true` means "I found something bad, no reason
+/// to go on searching".  `false` is only returned if we definitely cannot find anything
+/// bad anywhere.
+///
+/// The default implementations proceed structurally.
 trait Qualif {
     const IDX: usize;
 
@@ -285,7 +291,9 @@ trait Qualif {
     }
 }
 
-// Constant containing interior mutability (UnsafeCell).
+/// Constant containing interior mutability (UnsafeCell).
+/// This must be ruled out to make sure that evaluating the constant at compile-time
+/// and run-time would produce the same result.
 struct HasMutInterior;
 
 impl Qualif for HasMutInterior {
@@ -343,7 +351,9 @@ impl Qualif for HasMutInterior {
     }
 }
 
-// Constant containing an ADT that implements Drop.
+/// Constant containing an ADT that implements Drop.
+/// This must be ruled out because we cannot run `Drop` during compile-time
+/// as that might not be a `const fn`.
 struct NeedsDrop;
 
 impl Qualif for NeedsDrop {
@@ -366,8 +376,11 @@ impl Qualif for NeedsDrop {
     }
 }
 
-// Not promotable at all - non-`const fn` calls, asm!,
-// pointer comparisons, ptr-to-int casts, etc.
+/// Not promotable at all - non-`const fn` calls, asm!,
+/// pointer comparisons, ptr-to-int casts, etc.
+/// Inside a const context all constness rules apply, so promotion simply has to follow the regular
+/// constant rules (modulo interior mutability or `Drop` rules which are handled `HasMutInterior`
+/// and `NeedsDrop` respectively).
 struct IsNotPromotable;
 
 impl Qualif for IsNotPromotable {
@@ -511,12 +524,9 @@ impl Qualif for IsNotPromotable {
 
 /// Refers to temporaries which cannot be promoted *implicitly*.
 /// Explicit promotion happens e.g. for constant arguments declared via `rustc_args_required_const`.
-/// Inside a const context all constness rules
-/// apply, so implicit promotion simply has to follow the regular constant rules (modulo interior
-/// mutability or `Drop` rules which are handled `HasMutInterior` and `NeedsDrop` respectively).
-/// Implicit promotion inside regular functions does not happen if `const fn` calls are involved,
-/// as the call may be perfectly alright at runtime, but fail at compile time e.g. due to addresses
-/// being compared inside the function.
+/// Implicit promotion has almost the same rules, except that it does not happen if `const fn`
+/// calls are involved. The call may be perfectly alright at runtime, but fail at compile time
+/// e.g. due to addresses being compared inside the function.
 struct IsNotImplicitlyPromotable;
 
 impl Qualif for IsNotImplicitlyPromotable {
@@ -589,6 +599,11 @@ impl ConstCx<'_, 'tcx> {
     }
 }
 
+/// Checks MIR for const-correctness, using `ConstCx`
+/// for value qualifications, and accumulates writes of
+/// rvalue/call results to locals, in `local_qualif`.
+/// For functions (constant or not), it also records
+/// candidates for promotion in `promotion_candidates`.
 struct Checker<'a, 'tcx> {
     cx: ConstCx<'a, 'tcx>,
 
@@ -757,6 +772,9 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
                         // `let _: &'static _ = &(Cell::new(1), 2).1;`
                         let mut local_qualifs = self.qualifs_in_local(local);
                         local_qualifs[HasMutInterior] = false;
+                        // Make sure there is no reason to prevent promotion.
+                        // This is, in particular, the "implicit promotion" version of
+                        // the check making sure that we don't run drop glue during const-eval.
                         if !local_qualifs.0.iter().any(|&qualif| qualif) {
                             debug!("qualify_consts: promotion candidate: {:?}", candidate);
                             self.promotion_candidates.push(candidate);
@@ -920,11 +938,6 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
     }
 }
 
-/// Checks MIR for const-correctness, using `ConstCx`
-/// for value qualifications, and accumulates writes of
-/// rvalue/call results to locals, in `local_qualif`.
-/// For functions (constant or not), it also records
-/// candidates for promotion in `promotion_candidates`.
 impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
     fn visit_place_base(
         &mut self,

From 5aaf72f0f9fa8ec0119bd9d87b8a429fa86db982 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Mon, 3 Jun 2019 17:41:16 +0200
Subject: [PATCH 15/20] replace some mode comparisons by more readable function
 call, rename some Mode, and more comments

---
 src/librustc_mir/transform/qualify_consts.rs | 118 +++++++++++--------
 1 file changed, 72 insertions(+), 46 deletions(-)

diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 7b2c8af5e35e2..ce6834efeb964 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -35,11 +35,26 @@ use super::promote_consts::{self, Candidate, TempState};
 /// What kind of item we are in.
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 enum Mode {
-    Const,
+    /// A `static` item.
     Static,
+    /// A `static mut` item.
     StaticMut,
+    /// A `const fn` item.
     ConstFn,
-    Fn
+    /// A `const` item or an anonymous constant (e.g. in array lengths).
+    Const,
+    /// Other type of `fn`.
+    NonConstFn,
+}
+
+impl Mode {
+    /// Determine whether we are running in "const context".  "const context" refers
+    /// to code type-checked according to the rules of the "const type system":
+    /// the bodies of const/static items and `const fn`.
+    #[inline]
+    fn requires_const_checking(self) -> bool {
+        self != Mode::NonConstFn
+    }
 }
 
 impl fmt::Display for Mode {
@@ -48,7 +63,7 @@ impl fmt::Display for Mode {
             Mode::Const => write!(f, "constant"),
             Mode::Static | Mode::StaticMut => write!(f, "static"),
             Mode::ConstFn => write!(f, "constant function"),
-            Mode::Fn => write!(f, "function")
+            Mode::NonConstFn => write!(f, "function")
         }
     }
 }
@@ -135,10 +150,10 @@ enum ValueSource<'a, 'tcx> {
     },
 }
 
-/// A "qualif" is a way to lookg for something "bad" in the MIR that would prevent
-/// proper const evaluation.  So `return true` means "I found something bad, no reason
-/// to go on searching".  `false` is only returned if we definitely cannot find anything
-/// bad anywhere.
+/// A "qualif"(-ication) is a way to look for something "bad" in the MIR that would disqualify some
+/// code for promotion or prevent it from evaluating at compile time. So `return true` means
+/// "I found something bad, no reason to go on searching". `false` is only returned if we
+/// definitely cannot find anything bad anywhere.
 ///
 /// The default implementations proceed structurally.
 trait Qualif {
@@ -291,9 +306,11 @@ trait Qualif {
     }
 }
 
-/// Constant containing interior mutability (UnsafeCell).
+/// Constant containing interior mutability (`UnsafeCell<T>`).
 /// This must be ruled out to make sure that evaluating the constant at compile-time
-/// and run-time would produce the same result.
+/// and run-time would produce the same result. In particular, promotion of temporaries
+/// must not change program behavior; if the promoted could be written to, that would
+/// be a problem.
 struct HasMutInterior;
 
 impl Qualif for HasMutInterior {
@@ -322,10 +339,10 @@ impl Qualif for HasMutInterior {
                             _ => return true,
                         }
                     } else if let ty::Array(_, len) = ty.sty {
-                        // FIXME(eddyb) the `cx.mode == Mode::Fn` condition
+                        // FIXME(eddyb) the `cx.mode == Mode::NonConstFn` condition
                         // seems unnecessary, given that this is merely a ZST.
                         match len.assert_usize(cx.tcx) {
-                            Some(0) if cx.mode == Mode::Fn => {},
+                            Some(0) if cx.mode == Mode::NonConstFn => {},
                             _ => return true,
                         }
                     } else {
@@ -351,9 +368,10 @@ impl Qualif for HasMutInterior {
     }
 }
 
-/// Constant containing an ADT that implements Drop.
-/// This must be ruled out because we cannot run `Drop` during compile-time
-/// as that might not be a `const fn`.
+/// Constant containing an ADT that implements `Drop`.
+/// This must be ruled out (a) because we cannot run `Drop` during compile-time
+/// as that might not be a `const fn`, and (b) because implicit promotion would
+/// remove side-effects that occur as part of dropping that value.
 struct NeedsDrop;
 
 impl Qualif for NeedsDrop {
@@ -376,11 +394,12 @@ impl Qualif for NeedsDrop {
     }
 }
 
-/// Not promotable at all - non-`const fn` calls, asm!,
+/// Not promotable at all - non-`const fn` calls, `asm!`,
 /// pointer comparisons, ptr-to-int casts, etc.
 /// Inside a const context all constness rules apply, so promotion simply has to follow the regular
 /// constant rules (modulo interior mutability or `Drop` rules which are handled `HasMutInterior`
-/// and `NeedsDrop` respectively).
+/// and `NeedsDrop` respectively). Basically this duplicates the checks that the const-checking
+/// visitor enforces by emitting errors when working in const context.
 struct IsNotPromotable;
 
 impl Qualif for IsNotPromotable {
@@ -411,9 +430,10 @@ impl Qualif for IsNotPromotable {
             ProjectionElem::Index(_) => {}
 
             ProjectionElem::Field(..) => {
-                if cx.mode == Mode::Fn {
+                if cx.mode == Mode::NonConstFn {
                     let base_ty = proj.base.ty(cx.mir, cx.tcx).ty;
                     if let Some(def) = base_ty.ty_adt_def() {
+                        // No promotion of union field accesses.
                         if def.is_union() {
                             return true;
                         }
@@ -427,7 +447,7 @@ impl Qualif for IsNotPromotable {
 
     fn in_rvalue(cx: &ConstCx<'_, 'tcx>, rvalue: &Rvalue<'tcx>) -> bool {
         match *rvalue {
-            Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) if cx.mode == Mode::Fn => {
+            Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) if cx.mode == Mode::NonConstFn => {
                 let operand_ty = operand.ty(cx.mir, cx.tcx);
                 let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
                 let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
@@ -441,7 +461,7 @@ impl Qualif for IsNotPromotable {
                 }
             }
 
-            Rvalue::BinaryOp(op, ref lhs, _) if cx.mode == Mode::Fn => {
+            Rvalue::BinaryOp(op, ref lhs, _) if cx.mode == Mode::NonConstFn => {
                 if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(cx.mir, cx.tcx).sty {
                     assert!(op == BinOp::Eq || op == BinOp::Ne ||
                             op == BinOp::Le || op == BinOp::Lt ||
@@ -524,9 +544,9 @@ impl Qualif for IsNotPromotable {
 
 /// Refers to temporaries which cannot be promoted *implicitly*.
 /// Explicit promotion happens e.g. for constant arguments declared via `rustc_args_required_const`.
-/// Implicit promotion has almost the same rules, except that it does not happen if `const fn`
-/// calls are involved. The call may be perfectly alright at runtime, but fail at compile time
-/// e.g. due to addresses being compared inside the function.
+/// Implicit promotion has almost the same rules, except that disallows `const fn` except for
+/// those marked `#[rustc_promotable]`. This is to avoid changing a legitimate run-time operation
+/// into a failing compile-time operation e.g. due to addresses being compared inside the function.
 struct IsNotImplicitlyPromotable;
 
 impl Qualif for IsNotImplicitlyPromotable {
@@ -538,7 +558,7 @@ impl Qualif for IsNotImplicitlyPromotable {
         args: &[Operand<'tcx>],
         _return_ty: Ty<'tcx>,
     ) -> bool {
-        if cx.mode == Mode::Fn {
+        if cx.mode == Mode::NonConstFn {
             if let ty::FnDef(def_id, _) = callee.ty(cx.mir, cx.tcx).sty {
                 // Never promote runtime `const fn` calls of
                 // functions without `#[rustc_promotable]`.
@@ -602,8 +622,8 @@ impl ConstCx<'_, 'tcx> {
 /// Checks MIR for const-correctness, using `ConstCx`
 /// for value qualifications, and accumulates writes of
 /// rvalue/call results to locals, in `local_qualif`.
-/// For functions (constant or not), it also records
-/// candidates for promotion in `promotion_candidates`.
+/// It also records candidates for promotion in `promotion_candidates`,
+/// both in functions and const/static items.
 struct Checker<'a, 'tcx> {
     cx: ConstCx<'a, 'tcx>,
 
@@ -687,7 +707,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
     // slightly pointless (even with feature-gating).
     fn not_const(&mut self) {
         unleash_miri!(self);
-        if self.mode != Mode::Fn {
+        if self.mode.requires_const_checking() {
             let mut err = struct_span_err!(
                 self.tcx.sess,
                 self.span,
@@ -722,7 +742,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
                 qualifs[HasMutInterior] = false;
                 qualifs[IsNotPromotable] = true;
 
-                if self.mode != Mode::Fn {
+                if self.mode.requires_const_checking() {
                     if let BorrowKind::Mut { .. } = kind {
                         let mut err = struct_span_err!(self.tcx.sess,  self.span, E0017,
                                                        "references in {}s may only refer \
@@ -752,7 +772,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
 
                 // We might have a candidate for promotion.
                 let candidate = Candidate::Ref(location);
-                // We can only promote interior borrows of promotable temps.
+                // Start by traversing to the "base", with non-deref projections removed.
                 let mut place = place;
                 while let Place::Projection(ref proj) = *place {
                     if proj.elem == ProjectionElem::Deref {
@@ -761,6 +781,10 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
                     place = &proj.base;
                 }
                 debug!("qualify_consts: promotion candidate: place={:?}", place);
+                // We can only promote interior borrows of promotable temps (non-temps
+                // don't get promoted anyway).
+                // (If we bailed out of the loop due to a `Deref` above, we will definitely
+                // not enter the conditional here.)
                 if let Place::Base(PlaceBase::Local(local)) = *place {
                     if self.mir.local_kind(local) == LocalKind::Temp {
                         debug!("qualify_consts: promotion candidate: local={:?}", local);
@@ -771,10 +795,11 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
                         // `HasMutInterior`, from a type that does, e.g.:
                         // `let _: &'static _ = &(Cell::new(1), 2).1;`
                         let mut local_qualifs = self.qualifs_in_local(local);
-                        local_qualifs[HasMutInterior] = false;
-                        // Make sure there is no reason to prevent promotion.
+                        // Any qualifications, except HasMutInterior (see above), disqualify
+                        // from promotion.
                         // This is, in particular, the "implicit promotion" version of
                         // the check making sure that we don't run drop glue during const-eval.
+                        local_qualifs[HasMutInterior] = false;
                         if !local_qualifs.0.iter().any(|&qualif| qualif) {
                             debug!("qualify_consts: promotion candidate: {:?}", candidate);
                             self.promotion_candidates.push(candidate);
@@ -821,7 +846,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
         debug!("store to {:?} {:?}", kind, index);
 
         // Only handle promotable temps in non-const functions.
-        if self.mode == Mode::Fn {
+        if self.mode == Mode::NonConstFn {
             if kind != LocalKind::Temp ||
                !self.temp_promotion_state[index].is_promotable() {
                 return;
@@ -956,7 +981,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
                         .get_attrs(*def_id)
                         .iter()
                         .any(|attr| attr.check_name(sym::thread_local)) {
-                    if self.mode != Mode::Fn {
+                    if self.mode.requires_const_checking() {
                         span_err!(self.tcx.sess, self.span, E0625,
                                     "thread-local statics cannot be \
                                     accessed at compile-time");
@@ -980,7 +1005,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
                 }
                 unleash_miri!(self);
 
-                if self.mode != Mode::Fn {
+                if self.mode.requires_const_checking() {
                     let mut err = struct_span_err!(self.tcx.sess, self.span, E0013,
                                                     "{}s cannot refer to statics, use \
                                                     a constant instead", self.mode);
@@ -1018,7 +1043,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
                 }
                 let base_ty = proj.base.ty(self.mir, self.tcx).ty;
                 match self.mode {
-                    Mode::Fn => {},
+                    Mode::NonConstFn => {},
                     _ => {
                         if let ty::RawPtr(_) = base_ty.sty {
                             if !self.tcx.features().const_raw_ptr_deref {
@@ -1054,7 +1079,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
                                 }
                             },
 
-                            | Mode::Fn
+                            | Mode::NonConstFn
                             | Mode::Static
                             | Mode::StaticMut
                             | Mode::Const
@@ -1144,7 +1169,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
                 let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
                 match (cast_in, cast_out) {
                     (CastTy::Ptr(_), CastTy::Int(_)) |
-                    (CastTy::FnPtr, CastTy::Int(_)) if self.mode != Mode::Fn => {
+                    (CastTy::FnPtr, CastTy::Int(_)) if self.mode != Mode::NonConstFn => {
                         unleash_miri!(self);
                         if !self.tcx.features().const_raw_ptr_to_usize_cast {
                             // in const fn and constants require the feature gate
@@ -1171,7 +1196,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
                             op == BinOp::Offset);
 
                     unleash_miri!(self);
-                    if self.mode != Mode::Fn && !self.tcx.features().const_compare_raw_pointers {
+                    if self.mode.requires_const_checking() &&
+                        !self.tcx.features().const_compare_raw_pointers
+                    {
                         // require the feature gate inside constants and const fn
                         // FIXME: make it unsafe to use these operations
                         emit_feature_err(
@@ -1187,7 +1214,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
 
             Rvalue::NullaryOp(NullOp::Box, _) => {
                 unleash_miri!(self);
-                if self.mode != Mode::Fn {
+                if self.mode.requires_const_checking() {
                     let mut err = struct_span_err!(self.tcx.sess, self.span, E0010,
                                                    "allocations are not allowed in {}s", self.mode);
                     err.span_label(self.span, format!("allocation not allowed in {}s", self.mode));
@@ -1232,8 +1259,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
                                 // special intrinsic that can be called diretly without an intrinsic
                                 // feature gate needs a language feature gate
                                 "transmute" => {
-                                    // never promote transmute calls
-                                    if self.mode != Mode::Fn {
+                                    if self.mode.requires_const_checking() {
                                         // const eval transmute calls only with the feature gate
                                         if !self.tcx.features().const_transmute {
                                             emit_feature_err(
@@ -1256,7 +1282,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
                         }
                         _ => {
                             // In normal functions no calls are feature-gated.
-                            if self.mode != Mode::Fn {
+                            if self.mode.requires_const_checking() {
                                 let unleash_miri = self
                                     .tcx
                                     .sess
@@ -1315,7 +1341,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
                     }
                 }
                 ty::FnPtr(_) => {
-                    if self.mode != Mode::Fn {
+                    if self.mode.requires_const_checking() {
                         let mut err = self.tcx.sess.struct_span_err(
                             self.span,
                             &format!("function pointers are not allowed in const fn"));
@@ -1374,7 +1400,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
             self.super_terminator_kind(kind, location);
 
             // Deny *any* live drops anywhere other than functions.
-            if self.mode != Mode::Fn {
+            if self.mode.requires_const_checking() {
                 unleash_miri!(self);
                 // HACK(eddyb): emulate a bit of dataflow analysis,
                 // conservatively, that drop elaboration will do.
@@ -1485,12 +1511,12 @@ impl MirPass for QualifyAndPromoteConstants {
         let id = tcx.hir().as_local_hir_id(def_id).unwrap();
         let mut const_promoted_temps = None;
         let mode = match tcx.hir().body_owner_kind_by_hir_id(id) {
-            hir::BodyOwnerKind::Closure => Mode::Fn,
+            hir::BodyOwnerKind::Closure => Mode::NonConstFn,
             hir::BodyOwnerKind::Fn => {
                 if tcx.is_const_fn(def_id) {
                     Mode::ConstFn
                 } else {
-                    Mode::Fn
+                    Mode::NonConstFn
                 }
             }
             hir::BodyOwnerKind::Const => {
@@ -1502,7 +1528,7 @@ impl MirPass for QualifyAndPromoteConstants {
         };
 
         debug!("run_pass: mode={:?}", mode);
-        if mode == Mode::Fn || mode == Mode::ConstFn {
+        if mode == Mode::NonConstFn || mode == Mode::ConstFn {
             // This is ugly because Checker holds onto mir,
             // which can't be mutated until its scope ends.
             let (temps, candidates) = {

From 7e96bd080936a318b62e3ccaccca47b1c4e664e2 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Thu, 6 Jun 2019 11:47:52 +0200
Subject: [PATCH 16/20] avoid 'const-context' terminology

---
 src/librustc_mir/transform/qualify_consts.rs | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index ce6834efeb964..f7f3e61eaa489 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -48,9 +48,8 @@ enum Mode {
 }
 
 impl Mode {
-    /// Determine whether we are running in "const context".  "const context" refers
-    /// to code type-checked according to the rules of the "const type system":
-    /// the bodies of const/static items and `const fn`.
+    /// Determine whether we have to do full const-checking because syntactically, we
+    /// are required to be "const".
     #[inline]
     fn requires_const_checking(self) -> bool {
         self != Mode::NonConstFn

From 4dbd279df1ed4f6f9ab533cffe112d23a4fd45a7 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Thu, 6 Jun 2019 12:50:05 +0200
Subject: [PATCH 17/20] const-correctness might be confusing for C++ people

---
 src/librustc_mir/transform/qualify_consts.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index f7f3e61eaa489..aba4793941e61 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -618,7 +618,7 @@ impl ConstCx<'_, 'tcx> {
     }
 }
 
-/// Checks MIR for const-correctness, using `ConstCx`
+/// Checks MIR for being admissible as a compile-time constant, using `ConstCx`
 /// for value qualifications, and accumulates writes of
 /// rvalue/call results to locals, in `local_qualif`.
 /// It also records candidates for promotion in `promotion_candidates`,

From 38c7f3eff5a0f3630cac785f3f4191ceb1c2647b Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Thu, 6 Jun 2019 12:52:01 +0200
Subject: [PATCH 18/20] comments

---
 src/librustc_mir/transform/qualify_consts.rs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index aba4793941e61..46b34295881b4 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -307,9 +307,9 @@ trait Qualif {
 
 /// Constant containing interior mutability (`UnsafeCell<T>`).
 /// This must be ruled out to make sure that evaluating the constant at compile-time
-/// and run-time would produce the same result. In particular, promotion of temporaries
-/// must not change program behavior; if the promoted could be written to, that would
-/// be a problem.
+/// and at *any point* during the run-time would produce the same result. In particular,
+/// promotion of temporaries must not change program behavior; if the promoted could be
+/// written to, that would be a problem.
 struct HasMutInterior;
 
 impl Qualif for HasMutInterior {

From 1d045149f024f738c9175316a3660f6358ec86bf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= <matthias.krueger@famsik.de>
Date: Sun, 9 Jun 2019 21:37:26 +0200
Subject: [PATCH 19/20] submodules: update clippy from 71be6f62 to c0dbd34b

Changes:
````
travis: disable rls integration test.
rustup https://github.com/rust-lang/rust/pull/61669/
Add OUTER_EXPN_INFO lint
````
---
 src/tools/clippy | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/tools/clippy b/src/tools/clippy
index 71be6f62fa920..c0dbd34ba99a9 160000
--- a/src/tools/clippy
+++ b/src/tools/clippy
@@ -1 +1 @@
-Subproject commit 71be6f62fa920c0bd10cdf3a29aeb8c6719a8075
+Subproject commit c0dbd34ba99a949ece25c297a4a377685eb89c7c

From 35b5f4377028e34dc4df1ce67c225d2926c6c7a7 Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote <nnethercote@mozilla.com>
Date: Fri, 7 Jun 2019 12:08:38 +1000
Subject: [PATCH 20/20] Special-case literals in `parse_bottom_expr`.

This makes parsing faster, particularly for code with large constants,
for two reasons:
- it skips all the keyword comparisons for literals;
- it replaces the unnecessary `parse_literal_maybe_minus` call with
  `parse_lit`, avoiding an unnecessary allocation via `mk_expr`.
---
 src/libsyntax/parse/parser.rs | 32 ++++++++++++++++++++++----------
 1 file changed, 22 insertions(+), 10 deletions(-)

diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 43e7c9330e418..9b9954859be49 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -2002,8 +2002,29 @@ impl<'a> Parser<'a> {
 
         let ex: ExprKind;
 
+        macro_rules! parse_lit {
+            () => {
+                match self.parse_lit() {
+                    Ok(literal) => {
+                        hi = self.prev_span;
+                        ex = ExprKind::Lit(literal);
+                    }
+                    Err(mut err) => {
+                        self.cancel(&mut err);
+                        return Err(self.expected_expression_found());
+                    }
+                }
+            }
+        }
+
         // Note: when adding new syntax here, don't forget to adjust TokenKind::can_begin_expr().
         match self.token.kind {
+            // This match arm is a special-case of the `_` match arm below and
+            // could be removed without changing functionality, but it's faster
+            // to have it here, especially for programs with large constants.
+            token::Literal(_) => {
+                parse_lit!()
+            }
             token::OpenDelim(token::Paren) => {
                 self.bump();
 
@@ -2249,16 +2270,7 @@ impl<'a> Parser<'a> {
                         self.bump();
                         return Ok(self.mk_expr(self.span, ExprKind::Err, ThinVec::new()));
                     }
-                    match self.parse_literal_maybe_minus() {
-                        Ok(expr) => {
-                            hi = expr.span;
-                            ex = expr.node.clone();
-                        }
-                        Err(mut err) => {
-                            self.cancel(&mut err);
-                            return Err(self.expected_expression_found());
-                        }
-                    }
+                    parse_lit!()
                 }
             }
         }