about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-06-19 06:49:13 +0000
committerbors <bors@rust-lang.org>2019-06-19 06:49:13 +0000
commita6cbf2d1344418cd2807cc5380ef1247647a1e12 (patch)
treecd2c5efba7fae486762161de293c684b1d66d962
parent605ea9d05c48957a291eec11eb7339788c3140ed (diff)
parentfde341a4ef6a5728dfd1acb5de0b238918a2dd44 (diff)
downloadrust-a6cbf2d1344418cd2807cc5380ef1247647a1e12.tar.gz
rust-a6cbf2d1344418cd2807cc5380ef1247647a1e12.zip
Auto merge of #61945 - Centril:rollup-xdqo2mn, r=Centril
Rollup of 11 pull requests

Successful merges:

 - #61505 (Only show methods that appear in `impl` blocks in the Implementors sections of trait doc pages)
 - #61701 (move stray run-pass const tests into const/ folder)
 - #61748 (Tweak transparent enums and unions diagnostic spans)
 - #61802 (Make MaybeUninit #[repr(transparent)])
 - #61839 (ci: Add a script for generating CPU usage graphs)
 - #61842 (Remove unnecessary lift calls)
 - #61843 (Turn down the myriad-closures test)
 - #61896 (rustc_typeck: correctly compute `Substs` for `Res::SelfCtor`.)
 - #61898 (syntax: Factor out common fields from `SyntaxExtension` variants)
 - #61938 (create an issue for miri even in status test-fail)
 - #61941 (Preserve generator and yield source for error messages)

Failed merges:

r? @ghost
-rw-r--r--src/ci/cpu-usage-over-time.py19
-rw-r--r--src/doc/unstable-book/src/language-features/plugin.md2
-rwxr-xr-xsrc/etc/cpu-usage-over-time-plot.sh49
-rw-r--r--src/libcore/lib.rs1
-rw-r--r--src/libcore/mem/maybe_uninit.rs16
-rw-r--r--src/librustc/cfg/construct.rs2
-rw-r--r--src/librustc/hir/intravisit.rs2
-rw-r--r--src/librustc/hir/lowering.rs175
-rw-r--r--src/librustc/hir/mod.rs72
-rw-r--r--src/librustc/hir/print.rs2
-rw-r--r--src/librustc/ich/impls_hir.rs10
-rw-r--r--src/librustc/ich/impls_syntax.rs9
-rw-r--r--src/librustc/infer/canonical/canonicalizer.rs30
-rw-r--r--src/librustc/infer/canonical/mod.rs4
-rw-r--r--src/librustc/infer/canonical/query_response.rs16
-rw-r--r--src/librustc/infer/error_reporting/need_type_info.rs9
-rw-r--r--src/librustc/infer/opaque_types/mod.rs5
-rw-r--r--src/librustc/middle/expr_use_visitor.rs2
-rw-r--r--src/librustc/middle/liveness.rs2
-rw-r--r--src/librustc/middle/mem_categorization.rs5
-rw-r--r--src/librustc/middle/region.rs29
-rw-r--r--src/librustc/traits/codegen/mod.rs10
-rw-r--r--src/librustc/traits/project.rs1
-rw-r--r--src/librustc/traits/query/normalize.rs1
-rw-r--r--src/librustc/traits/query/type_op/mod.rs6
-rw-r--r--src/librustc/traits/query/type_op/normalize.rs2
-rw-r--r--src/librustc/traits/specialize/mod.rs7
-rw-r--r--src/librustc/ty/error.rs9
-rw-r--r--src/librustc/ty/sty.rs13
-rw-r--r--src/librustc_allocator/expand.rs21
-rw-r--r--src/librustc_metadata/creader.rs50
-rw-r--r--src/librustc_metadata/cstore_impl.rs13
-rw-r--r--src/librustc_metadata/decoder.rs7
-rw-r--r--src/librustc_mir/borrow_check/mod.rs2
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/mod.rs4
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs4
-rw-r--r--src/librustc_mir/build/expr/as_rvalue.rs4
-rw-r--r--src/librustc_mir/build/mod.rs4
-rw-r--r--src/librustc_mir/dataflow/drop_flag_effects.rs2
-rw-r--r--src/librustc_mir/hair/constant.rs2
-rw-r--r--src/librustc_mir/hair/cx/expr.rs2
-rw-r--r--src/librustc_mir/hair/cx/mod.rs7
-rw-r--r--src/librustc_mir/hair/pattern/_match.rs2
-rw-r--r--src/librustc_passes/rvalue_promotion.rs2
-rw-r--r--src/librustc_plugin/registry.rs22
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs5
-rw-r--r--src/librustc_resolve/lib.rs12
-rw-r--r--src/librustc_resolve/macros.rs57
-rw-r--r--src/librustc_traits/normalize_erasing_regions.rs3
-rw-r--r--src/librustc_typeck/check/expr.rs2
-rw-r--r--src/librustc_typeck/check/generator_interior.rs43
-rw-r--r--src/librustc_typeck/check/mod.rs209
-rw-r--r--src/librustdoc/clean/inline.rs12
-rw-r--r--src/librustdoc/html/render.rs21
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs4
-rw-r--r--src/libsyntax/ext/base.rs174
-rw-r--r--src/libsyntax/ext/derive.rs13
-rw-r--r--src/libsyntax/ext/expand.rs180
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs12
-rw-r--r--src/libsyntax/std_inject.rs12
-rw-r--r--src/libsyntax/test.rs13
-rw-r--r--src/libsyntax_ext/deriving/mod.rs40
-rw-r--r--src/libsyntax_ext/lib.rs70
-rw-r--r--src/libsyntax_ext/proc_macro_decls.rs16
-rw-r--r--src/libsyntax_ext/test.rs15
-rw-r--r--src/libsyntax_ext/test_case.rs15
-rw-r--r--src/libsyntax_pos/hygiene.rs73
-rw-r--r--src/test/run-pass-fulldeps/auxiliary/plugin-args.rs18
-rw-r--r--src/test/run-pass-fulldeps/myriad-closures.rs6
-rw-r--r--src/test/run-pass/consts/assoc-const.rs (renamed from src/test/run-pass/ctfe/assoc-const.rs)0
-rw-r--r--src/test/run-pass/consts/bswap-const.rs (renamed from src/test/run-pass/ctfe/bswap-const.rs)0
-rw-r--r--src/test/run-pass/consts/chained-constants-stackoverflow.rs (renamed from src/test/run-pass/ctfe/chained-constants-stackoverflow.rs)0
-rw-r--r--src/test/run-pass/consts/const-block-non-item-statement-3.rs (renamed from src/test/run-pass/ctfe/const-block-non-item-statement-3.rs)0
-rw-r--r--src/test/run-pass/consts/const-block-non-item-statement.rs (renamed from src/test/run-pass/ctfe/const-block-non-item-statement.rs)0
-rw-r--r--src/test/run-pass/consts/const-fn-type-name.rs (renamed from src/test/run-pass/ctfe/const-fn-type-name.rs)0
-rw-r--r--src/test/run-pass/consts/const-int-conversion.rs (renamed from src/test/run-pass/const-int-conversion.rs)0
-rw-r--r--src/test/run-pass/consts/const-int-overflowing.rs (renamed from src/test/run-pass/const-int-overflowing.rs)0
-rw-r--r--src/test/run-pass/consts/const-int-rotate.rs (renamed from src/test/run-pass/const-int-rotate.rs)0
-rw-r--r--src/test/run-pass/consts/const-int-saturating-arith.rs (renamed from src/test/run-pass/const-int-saturating-arith.rs)0
-rw-r--r--src/test/run-pass/consts/const-int-sign.rs (renamed from src/test/run-pass/const-int-sign.rs)0
-rw-r--r--src/test/run-pass/consts/const-int-wrapping.rs (renamed from src/test/run-pass/const-int-wrapping.rs)0
-rw-r--r--src/test/run-pass/consts/const-needs_drop.rs (renamed from src/test/run-pass/const-needs_drop.rs)0
-rw-r--r--src/test/run-pass/consts/deref_in_pattern.rs (renamed from src/test/run-pass/ctfe/deref_in_pattern.rs)0
-rw-r--r--src/test/run-pass/consts/ice-48279.rs (renamed from src/test/run-pass/ctfe/ice-48279.rs)0
-rw-r--r--src/test/run-pass/consts/issue-37550.rs (renamed from src/test/run-pass/ctfe/issue-37550.rs)0
-rw-r--r--src/test/run-pass/consts/issue-broken-mir.rs (renamed from src/test/run-pass/ctfe/issue-broken-mir.rs)0
-rw-r--r--src/test/run-pass/consts/locals-in-const-fn.rs (renamed from src/test/run-pass/ctfe/locals-in-const-fn.rs)0
-rw-r--r--src/test/run-pass/consts/match-const-fn-structs.rs (renamed from src/test/run-pass/ctfe/match-const-fn-structs.rs)0
-rw-r--r--src/test/run-pass/consts/mozjs-error.rs (renamed from src/test/run-pass/ctfe/mozjs-error.rs)0
-rw-r--r--src/test/run-pass/consts/non-scalar-cast.rs (renamed from src/test/run-pass/ctfe/non-scalar-cast.rs)0
-rw-r--r--src/test/run-pass/consts/promotion.rs (renamed from src/test/run-pass/ctfe/promotion.rs)0
-rw-r--r--src/test/run-pass/consts/references.rs (renamed from src/test/run-pass/ctfe/references.rs)0
-rw-r--r--src/test/run-pass/consts/repeat_match.rs (renamed from src/test/run-pass/ctfe/repeat_match.rs)0
-rw-r--r--src/test/run-pass/consts/return-in-const-fn.rs (renamed from src/test/run-pass/ctfe/return-in-const-fn.rs)0
-rw-r--r--src/test/run-pass/consts/signed_enum_discr.rs (renamed from src/test/run-pass/ctfe/signed_enum_discr.rs)0
-rw-r--r--src/test/run-pass/consts/transmute-const.rs (renamed from src/test/run-pass/ctfe/transmute-const.rs)0
-rw-r--r--src/test/run-pass/consts/tuple-struct-constructors.rs (renamed from src/test/run-pass/ctfe/tuple-struct-constructors.rs)0
-rw-r--r--src/test/ui/async-await/unresolved_type_param.rs4
-rw-r--r--src/test/ui/async-await/unresolved_type_param.stderr4
-rw-r--r--src/test/ui/feature-gates/feature-gate-transparent_enums.stderr6
-rw-r--r--src/test/ui/feature-gates/feature-gate-transparent_unions.stderr7
-rw-r--r--src/test/ui/issues/issue-57924.rs (renamed from src/test/run-pass/issues/issue-57924.rs)1
-rw-r--r--src/test/ui/issues/issue-57924.stderr9
-rw-r--r--src/test/ui/issues/issue-61882-2.rs11
-rw-r--r--src/test/ui/issues/issue-61882-2.stderr15
-rw-r--r--src/test/ui/issues/issue-61882.rs9
-rw-r--r--src/test/ui/issues/issue-61882.stderr21
-rw-r--r--src/test/ui/repr/repr-transparent.stderr94
-rwxr-xr-xsrc/tools/publish_toolstate.py25
109 files changed, 966 insertions, 923 deletions
diff --git a/src/ci/cpu-usage-over-time.py b/src/ci/cpu-usage-over-time.py
index 78427a6360a..daf21670b33 100644
--- a/src/ci/cpu-usage-over-time.py
+++ b/src/ci/cpu-usage-over-time.py
@@ -30,23 +30,8 @@
 # the second column is always zero.
 #
 # Once you've downloaded a file there's various ways to plot it and visualize
-# it. For command line usage you can use a script like so:
-#
-#      set timefmt '%Y-%m-%dT%H:%M:%S'
-#      set xdata time
-#      set ylabel "Idle CPU %"
-#      set xlabel "Time"
-#      set datafile sep ','
-#      set term png
-#      set output "printme.png"
-#      set grid
-#      builder = "i686-apple"
-#      plot "cpu-".builder.".csv" using 1:2 with lines title builder
-#
-# Executed as `gnuplot < ./foo.plot` it will generate a graph called
-# `printme.png` which you can then open up. If you know how to improve this
-# script or the viewing process that would be much appreciated :) (or even if
-# you know how to automate it!)
+# it. For command line usage you use the `src/etc/cpu-usage-over-time-plot.sh`
+# script in this repository.
 
 import datetime
 import sys
diff --git a/src/doc/unstable-book/src/language-features/plugin.md b/src/doc/unstable-book/src/language-features/plugin.md
index 1994cf49188..0e38e2865d8 100644
--- a/src/doc/unstable-book/src/language-features/plugin.md
+++ b/src/doc/unstable-book/src/language-features/plugin.md
@@ -132,7 +132,7 @@ The advantages over a simple `fn(&str) -> u32` are:
 In addition to procedural macros, you can define new
 [`derive`](../../reference/attributes/derive.md)-like attributes and other kinds
 of extensions.  See `Registry::register_syntax_extension` and the
-`SyntaxExtension` enum.  For a more involved macro example, see
+`SyntaxExtension` struct.  For a more involved macro example, see
 [`regex_macros`](https://github.com/rust-lang/regex/blob/master/regex_macros/src/lib.rs).
 
 
diff --git a/src/etc/cpu-usage-over-time-plot.sh b/src/etc/cpu-usage-over-time-plot.sh
new file mode 100755
index 00000000000..724a21c3fc2
--- /dev/null
+++ b/src/etc/cpu-usage-over-time-plot.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+
+# A small script to help visualizing CPU usage over time data collected on CI
+# using `gnuplot`.
+#
+# This script is expected to be called with two arguments. The first is the full
+# commit SHA of the build you're interested in, and the second is the name of
+# the builder. For example:
+#
+#  ./src/etc/cpu-usage-over-time-plot.sh e699ea096fcc2fc9ce8e8bcf884e11496a31cc9f i686-mingw-1
+#
+# That will generate `$builder.png` in the current directory which you can open
+# up to see a hopefully pretty graph.
+#
+# Improvements to this script are greatly appreciated!
+
+set -ex
+
+bucket=rust-lang-ci-evalazure
+commit=$1
+builder=$2
+
+curl -O https://$bucket.s3.amazonaws.com/rustc-builds/$commit/cpu-$builder.csv
+
+gnuplot <<-EOF
+reset
+set timefmt '%Y-%m-%dT%H:%M:%S'
+set xdata time
+set ylabel "CPU Usage %"
+set xlabel "Time"
+set datafile sep ','
+set term png size 3000,1000
+set output "$builder.png"
+set grid
+
+f(x) = mean_y
+fit f(x) 'cpu-$builder.csv' using 1:(100-\$2) via mean_y
+
+set label 1 gprintf("Average = %g%%", mean_y) center font ",18"
+set label 1 at graph 0.50, 0.25
+set xtics rotate by 45 offset -2,-2.4 300
+set ytics 10
+set boxwidth 0.5
+
+plot \\
+   mean_y with lines linetype 1 linecolor rgb "#ff0000" title "average", \\
+   "cpu-$builder.csv" using 1:(100-\$2) with points pointtype 7 pointsize 0.4 title "$builder", \\
+   "" using 1:(100-\$2) smooth bezier linewidth 3 title "bezier"
+EOF
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 030f4f1d12c..1bfb852424d 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -100,6 +100,7 @@
 #![feature(staged_api)]
 #![feature(std_internals)]
 #![feature(stmt_expr_attributes)]
+#![cfg_attr(not(bootstrap), feature(transparent_unions))]
 #![feature(unboxed_closures)]
 #![feature(unsized_locals)]
 #![feature(untagged_unions)]
diff --git a/src/libcore/mem/maybe_uninit.rs b/src/libcore/mem/maybe_uninit.rs
index eeff9d0303a..28e1e22ba7f 100644
--- a/src/libcore/mem/maybe_uninit.rs
+++ b/src/libcore/mem/maybe_uninit.rs
@@ -172,7 +172,7 @@ use crate::mem::ManuallyDrop;
 ///
 /// # Layout
 ///
-/// `MaybeUninit<T>` is guaranteed to have the same size and alignment as `T`:
+/// `MaybeUninit<T>` is guaranteed to have the same size, alignment, and ABI as `T`:
 ///
 /// ```rust
 /// use std::mem::{MaybeUninit, size_of, align_of};
@@ -191,9 +191,23 @@ use crate::mem::ManuallyDrop;
 /// assert_eq!(size_of::<Option<bool>>(), 1);
 /// assert_eq!(size_of::<Option<MaybeUninit<bool>>>(), 2);
 /// ```
+///
+/// If `T` is FFI-safe, then so is `MaybeUninit<T>`.
+///
+/// While `MaybeUninit` is `#[repr(transparent)]` (indicating it guarantees the same size,
+/// alignment, and ABI as `T`), this does *not* change any of the previous caveats. `Option<T>` and
+/// `Option<MaybeUninit<T>>` may still have different sizes, and types containing a field of type
+/// `T` may be laid out (and sized) differently than if that field were `MaybeUninit<T>`.
+/// `MaybeUninit` is a union type, and `#[repr(transparent)]` on unions is unstable (see [the
+/// tracking issue](https://github.com/rust-lang/rust/issues/60405)). Over time, the exact
+/// guarantees of `#[repr(transparent)]` on unions may evolve, and `MaybeUninit` may or may not
+/// remain `#[repr(transparent)]`. That said, `MaybeUninit<T>` will *always* guarantee that it has
+/// the same size, alignment, and ABI as `T`; it's just that the way `MaybeUninit` implements that
+/// guarantee may evolve.
 #[allow(missing_debug_implementations)]
 #[stable(feature = "maybe_uninit", since = "1.36.0")]
 #[derive(Copy)]
+#[cfg_attr(not(bootstrap), repr(transparent))]
 pub union MaybeUninit<T> {
     uninit: (),
     value: ManuallyDrop<T>,
diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index 213e57a3b37..a7750edbb6f 100644
--- a/src/librustc/cfg/construct.rs
+++ b/src/librustc/cfg/construct.rs
@@ -330,7 +330,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
             hir::ExprKind::DropTemps(ref e) |
             hir::ExprKind::Unary(_, ref e) |
             hir::ExprKind::Field(ref e, _) |
-            hir::ExprKind::Yield(ref e) |
+            hir::ExprKind::Yield(ref e, _) |
             hir::ExprKind::Repeat(ref e, _) => {
                 self.straightline(expr, pred, Some(&**e).into_iter())
             }
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index e29a373ec3b..8d7e51d1ea6 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -1089,7 +1089,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
                 visitor.visit_expr(expr)
             }
         }
-        ExprKind::Yield(ref subexpression) => {
+        ExprKind::Yield(ref subexpression, _) => {
             visitor.visit_expr(subexpression);
         }
         ExprKind::Lit(_) | ExprKind::Err => {}
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index c4f7b78a133..60b099b0fed 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -62,14 +62,14 @@ use syntax::errors;
 use syntax::ext::hygiene::{Mark, SyntaxContext};
 use syntax::print::pprust;
 use syntax::ptr::P;
-use syntax::source_map::{self, respan, CompilerDesugaringKind, Spanned};
+use syntax::source_map::{self, respan, ExpnInfo, CompilerDesugaringKind, Spanned};
 use syntax::source_map::CompilerDesugaringKind::IfTemporary;
 use syntax::std_inject;
 use syntax::symbol::{kw, sym, Symbol};
 use syntax::tokenstream::{TokenStream, TokenTree};
 use syntax::parse::token::{self, Token};
 use syntax::visit::{self, Visitor};
-use syntax_pos::{DUMMY_SP, edition, Span};
+use syntax_pos::{DUMMY_SP, Span};
 
 const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF;
 
@@ -95,8 +95,7 @@ pub struct LoweringContext<'a> {
 
     modules: BTreeMap<NodeId, hir::ModuleItems>,
 
-    is_generator: bool,
-    is_async_body: bool,
+    generator_kind: Option<hir::GeneratorKind>,
 
     /// Used to get the current `fn`'s def span to point to when using `await`
     /// outside of an `async fn`.
@@ -142,6 +141,9 @@ pub struct LoweringContext<'a> {
     current_hir_id_owner: Vec<(DefIndex, u32)>,
     item_local_id_counters: NodeMap<u32>,
     node_id_to_hir_id: IndexVec<NodeId, hir::HirId>,
+
+    allow_try_trait: Option<Lrc<[Symbol]>>,
+    allow_gen_future: Option<Lrc<[Symbol]>>,
 }
 
 pub trait Resolver {
@@ -261,12 +263,13 @@ pub fn lower_crate(
         current_hir_id_owner: vec![(CRATE_DEF_INDEX, 0)],
         item_local_id_counters: Default::default(),
         node_id_to_hir_id: IndexVec::new(),
-        is_generator: false,
-        is_async_body: false,
+        generator_kind: None,
         current_item: None,
         lifetimes_to_define: Vec::new(),
         is_collecting_in_band_lifetimes: false,
         in_scope_lifetimes: Vec::new(),
+        allow_try_trait: Some([sym::try_trait][..].into()),
+        allow_gen_future: Some([sym::gen_future][..].into()),
     }.lower_crate(krate)
 }
 
@@ -790,18 +793,49 @@ impl<'a> LoweringContext<'a> {
         })
     }
 
-    fn record_body(&mut self, arguments: HirVec<hir::Arg>, value: hir::Expr) -> hir::BodyId {
-        if self.is_generator && self.is_async_body {
-            span_err!(
-                self.sess,
-                value.span,
-                E0727,
-                "`async` generators are not yet supported",
-            );
-            self.sess.abort_if_errors();
+    fn generator_movability_for_fn(
+        &mut self,
+        decl: &ast::FnDecl,
+        fn_decl_span: Span,
+        generator_kind: Option<hir::GeneratorKind>,
+        movability: Movability,
+    ) -> Option<hir::GeneratorMovability> {
+        match generator_kind {
+            Some(hir::GeneratorKind::Gen) =>  {
+                if !decl.inputs.is_empty() {
+                    span_err!(
+                        self.sess,
+                        fn_decl_span,
+                        E0628,
+                        "generators cannot have explicit arguments"
+                    );
+                    self.sess.abort_if_errors();
+                }
+                Some(match movability {
+                    Movability::Movable => hir::GeneratorMovability::Movable,
+                    Movability::Static => hir::GeneratorMovability::Static,
+                })
+            },
+            Some(hir::GeneratorKind::Async) => {
+                bug!("non-`async` closure body turned `async` during lowering");
+            },
+            None => {
+                if movability == Movability::Static {
+                    span_err!(
+                        self.sess,
+                        fn_decl_span,
+                        E0697,
+                        "closures cannot be static"
+                    );
+                }
+                None
+            },
         }
+    }
+
+    fn record_body(&mut self, arguments: HirVec<hir::Arg>, value: hir::Expr) -> hir::BodyId {
         let body = hir::Body {
-            is_generator: self.is_generator || self.is_async_body,
+            generator_kind: self.generator_kind,
             arguments,
             value,
         };
@@ -848,14 +882,10 @@ impl<'a> LoweringContext<'a> {
         allow_internal_unstable: Option<Lrc<[Symbol]>>,
     ) -> Span {
         let mark = Mark::fresh(Mark::root());
-        mark.set_expn_info(source_map::ExpnInfo {
-            call_site: span,
+        mark.set_expn_info(ExpnInfo {
             def_site: Some(span),
-            format: source_map::CompilerDesugaring(reason),
             allow_internal_unstable,
-            allow_internal_unsafe: false,
-            local_inner_macros: false,
-            edition: edition::Edition::from_session(),
+            ..ExpnInfo::default(source_map::CompilerDesugaring(reason), span, self.sess.edition())
         });
         span.with_ctxt(SyntaxContext::empty().apply_mark(mark))
     }
@@ -1142,7 +1172,7 @@ impl<'a> LoweringContext<'a> {
         };
         let decl = self.lower_fn_decl(&ast_decl, None, /* impl trait allowed */ false, None);
         let body_id = self.lower_fn_body(&ast_decl, |this| {
-            this.is_async_body = true;
+            this.generator_kind = Some(hir::GeneratorKind::Async);
             body(this)
         });
         let generator = hir::Expr {
@@ -1156,7 +1186,7 @@ impl<'a> LoweringContext<'a> {
         let unstable_span = self.mark_span_with_reason(
             CompilerDesugaringKind::Async,
             span,
-            Some(vec![sym::gen_future].into()),
+            self.allow_gen_future.clone(),
         );
         let gen_future = self.expr_std_path(
             unstable_span, &[sym::future, sym::from_generator], None, ThinVec::new());
@@ -1167,12 +1197,10 @@ impl<'a> LoweringContext<'a> {
         &mut self,
         f: impl FnOnce(&mut LoweringContext<'_>) -> (HirVec<hir::Arg>, hir::Expr),
     ) -> hir::BodyId {
-        let prev_is_generator = mem::replace(&mut self.is_generator, false);
-        let prev_is_async_body = mem::replace(&mut self.is_async_body, false);
+        let prev_gen_kind = self.generator_kind.take();
         let (arguments, result) = f(self);
         let body_id = self.record_body(arguments, result);
-        self.is_generator = prev_is_generator;
-        self.is_async_body = prev_is_async_body;
+        self.generator_kind = prev_gen_kind;
         body_id
     }
 
@@ -4382,7 +4410,7 @@ impl<'a> LoweringContext<'a> {
                     let unstable_span = this.mark_span_with_reason(
                         CompilerDesugaringKind::TryBlock,
                         body.span,
-                        Some(vec![sym::try_trait].into()),
+                        this.allow_try_trait.clone(),
                     );
                     let mut block = this.lower_block(body, true).into_inner();
                     let tail = block.expr.take().map_or_else(
@@ -4475,37 +4503,18 @@ impl<'a> LoweringContext<'a> {
 
                     self.with_new_scopes(|this| {
                         this.current_item = Some(fn_decl_span);
-                        let mut is_generator = false;
+                        let mut generator_kind = None;
                         let body_id = this.lower_fn_body(decl, |this| {
                             let e = this.lower_expr(body);
-                            is_generator = this.is_generator;
+                            generator_kind = this.generator_kind;
                             e
                         });
-                        let generator_option = if is_generator {
-                            if !decl.inputs.is_empty() {
-                                span_err!(
-                                    this.sess,
-                                    fn_decl_span,
-                                    E0628,
-                                    "generators cannot have explicit arguments"
-                                );
-                                this.sess.abort_if_errors();
-                            }
-                            Some(match movability {
-                                Movability::Movable => hir::GeneratorMovability::Movable,
-                                Movability::Static => hir::GeneratorMovability::Static,
-                            })
-                        } else {
-                            if movability == Movability::Static {
-                                span_err!(
-                                    this.sess,
-                                    fn_decl_span,
-                                    E0697,
-                                    "closures cannot be static"
-                                );
-                            }
-                            None
-                        };
+                        let generator_option = this.generator_movability_for_fn(
+                            &decl,
+                            fn_decl_span,
+                            generator_kind,
+                            movability,
+                        );
                         hir::ExprKind::Closure(
                             this.lower_capture_clause(capture_clause),
                             fn_decl,
@@ -4677,12 +4686,26 @@ impl<'a> LoweringContext<'a> {
             }
 
             ExprKind::Yield(ref opt_expr) => {
-                self.is_generator = true;
+                match self.generator_kind {
+                    Some(hir::GeneratorKind::Gen) => {},
+                    Some(hir::GeneratorKind::Async) => {
+                        span_err!(
+                            self.sess,
+                            e.span,
+                            E0727,
+                            "`async` generators are not yet supported",
+                        );
+                        self.sess.abort_if_errors();
+                    },
+                    None => {
+                        self.generator_kind = Some(hir::GeneratorKind::Gen);
+                    }
+                }
                 let expr = opt_expr
                     .as_ref()
                     .map(|x| self.lower_expr(x))
                     .unwrap_or_else(|| self.expr_unit(e.span));
-                hir::ExprKind::Yield(P(expr))
+                hir::ExprKind::Yield(P(expr), hir::YieldSource::Yield)
             }
 
             ExprKind::Err => hir::ExprKind::Err,
@@ -4968,13 +4991,13 @@ impl<'a> LoweringContext<'a> {
                 let unstable_span = self.mark_span_with_reason(
                     CompilerDesugaringKind::QuestionMark,
                     e.span,
-                    Some(vec![sym::try_trait].into()),
+                    self.allow_try_trait.clone(),
                 );
                 let try_span = self.sess.source_map().end_point(e.span);
                 let try_span = self.mark_span_with_reason(
                     CompilerDesugaringKind::QuestionMark,
                     try_span,
-                    Some(vec![sym::try_trait].into()),
+                    self.allow_try_trait.clone(),
                 );
 
                 // `Try::into_result(<expr>)`
@@ -5754,19 +5777,23 @@ impl<'a> LoweringContext<'a> {
         //         yield ();
         //     }
         // }
-        if !self.is_async_body {
-            let mut err = struct_span_err!(
-                self.sess,
-                await_span,
-                E0728,
-                "`await` is only allowed inside `async` functions and blocks"
-            );
-            err.span_label(await_span, "only allowed inside `async` functions and blocks");
-            if let Some(item_sp) = self.current_item {
-                err.span_label(item_sp, "this is not `async`");
+        match self.generator_kind {
+            Some(hir::GeneratorKind::Async) => {},
+            Some(hir::GeneratorKind::Gen) |
+            None => {
+                let mut err = struct_span_err!(
+                    self.sess,
+                    await_span,
+                    E0728,
+                    "`await` is only allowed inside `async` functions and blocks"
+                );
+                err.span_label(await_span, "only allowed inside `async` functions and blocks");
+                if let Some(item_sp) = self.current_item {
+                    err.span_label(item_sp, "this is not `async`");
+                }
+                err.emit();
+                return hir::ExprKind::Err;
             }
-            err.emit();
-            return hir::ExprKind::Err;
         }
         let span = self.mark_span_with_reason(
             CompilerDesugaringKind::Await,
@@ -5776,7 +5803,7 @@ impl<'a> LoweringContext<'a> {
         let gen_future_span = self.mark_span_with_reason(
             CompilerDesugaringKind::Await,
             await_span,
-            Some(vec![sym::gen_future].into()),
+            self.allow_gen_future.clone(),
         );
 
         // let mut pinned = <expr>;
@@ -5864,7 +5891,7 @@ impl<'a> LoweringContext<'a> {
             let unit = self.expr_unit(span);
             let yield_expr = P(self.expr(
                 span,
-                hir::ExprKind::Yield(P(unit)),
+                hir::ExprKind::Yield(P(unit), hir::YieldSource::Await),
                 ThinVec::new(),
             ));
             self.stmt(span, hir::StmtKind::Expr(yield_expr))
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index a88eeaa5ee2..69bd4d3f1f6 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1306,7 +1306,7 @@ pub struct BodyId {
 ///
 /// - an `arguments` array containing the `(x, y)` pattern
 /// - a `value` containing the `x + y` expression (maybe wrapped in a block)
-/// - `is_generator` would be false
+/// - `generator_kind` would be `None`
 ///
 /// All bodies have an **owner**, which can be accessed via the HIR
 /// map using `body_owner_def_id()`.
@@ -1314,7 +1314,7 @@ pub struct BodyId {
 pub struct Body {
     pub arguments: HirVec<Arg>,
     pub value: Expr,
-    pub is_generator: bool,
+    pub generator_kind: Option<GeneratorKind>,
 }
 
 impl Body {
@@ -1325,6 +1325,26 @@ impl Body {
     }
 }
 
+/// The type of source expression that caused this generator to be created.
+// Not `IsAsync` because we want to eventually add support for `AsyncGen`
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, HashStable,
+         RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+pub enum GeneratorKind {
+    /// An `async` block or function.
+    Async,
+    /// A generator literal created via a `yield` inside a closure.
+    Gen,
+}
+
+impl fmt::Display for GeneratorKind {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str(match self {
+            GeneratorKind::Async => "`async` object",
+            GeneratorKind::Gen => "generator",
+        })
+    }
+}
+
 #[derive(Copy, Clone, Debug)]
 pub enum BodyOwnerKind {
     /// Functions and methods.
@@ -1531,8 +1551,8 @@ pub enum ExprKind {
     ///
     /// The final span is the span of the argument block `|...|`.
     ///
-    /// This may also be a generator literal, indicated by the final boolean,
-    /// in that case there is an `GeneratorClause`.
+    /// This may also be a generator literal or an `async block` as indicated by the
+    /// `Option<GeneratorMovability>`.
     Closure(CaptureClause, P<FnDecl>, BodyId, Span, Option<GeneratorMovability>),
     /// A block (e.g., `'label: { ... }`).
     Block(P<Block>, Option<Label>),
@@ -1576,7 +1596,7 @@ pub enum ExprKind {
     Repeat(P<Expr>, AnonConst),
 
     /// A suspension point for generators (i.e., `yield <expr>`).
-    Yield(P<Expr>),
+    Yield(P<Expr>, YieldSource),
 
     /// A placeholder for an expression that wasn't syntactically well formed in some way.
     Err,
@@ -1668,12 +1688,12 @@ pub enum LoopIdError {
 
 impl fmt::Display for LoopIdError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Display::fmt(match *self {
+        f.write_str(match self {
             LoopIdError::OutsideLoopScope => "not inside loop scope",
             LoopIdError::UnlabeledCfInWhileCondition =>
                 "unlabeled control flow (break or continue) in while condition",
             LoopIdError::UnresolvedLabel => "label not found",
-        }, f)
+        })
     }
 }
 
@@ -1687,13 +1707,34 @@ pub struct Destination {
     pub target_id: Result<HirId, LoopIdError>,
 }
 
+/// Whether a generator contains self-references, causing it to be `!Unpin`.
 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, HashStable,
          RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
 pub enum GeneratorMovability {
+    /// May contain self-references, `!Unpin`.
     Static,
+    /// Must not contain self-references, `Unpin`.
     Movable,
 }
 
+/// The yield kind that caused an `ExprKind::Yield`.
+#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)]
+pub enum YieldSource {
+    /// An `<expr>.await`.
+    Await,
+    /// A plain `yield`.
+    Yield,
+}
+
+impl fmt::Display for YieldSource {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str(match self {
+            YieldSource::Await => "`await`",
+            YieldSource::Yield => "`yield`",
+        })
+    }
+}
+
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug, Copy, HashStable)]
 pub enum CaptureClause {
     CaptureByValue,
@@ -2058,11 +2099,10 @@ impl Defaultness {
 
 impl fmt::Display for Unsafety {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Display::fmt(match *self {
-                              Unsafety::Normal => "normal",
-                              Unsafety::Unsafe => "unsafe",
-                          },
-                          f)
+        f.write_str(match self {
+            Unsafety::Normal => "normal",
+            Unsafety::Unsafe => "unsafe",
+        })
     }
 }
 
@@ -2076,10 +2116,10 @@ pub enum ImplPolarity {
 
 impl fmt::Debug for ImplPolarity {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self {
-            ImplPolarity::Positive => "positive".fmt(f),
-            ImplPolarity::Negative => "negative".fmt(f),
-        }
+        f.write_str(match self {
+            ImplPolarity::Positive => "positive",
+            ImplPolarity::Negative => "negative",
+        })
     }
 }
 
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 7b0a499fa5c..69ee84dfa43 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -1501,7 +1501,7 @@ impl<'a> State<'a> {
 
                 self.pclose()?;
             }
-            hir::ExprKind::Yield(ref expr) => {
+            hir::ExprKind::Yield(ref expr, _) => {
                 self.word_space("yield")?;
                 self.print_expr_maybe_paren(&expr, parser::PREC_JUMP)?;
             }
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
index f2f909b6af1..30d76f240d1 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -335,15 +335,15 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::Body {
                                           hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let hir::Body {
-            ref arguments,
-            ref value,
-            is_generator,
-        } = *self;
+            arguments,
+            value,
+            generator_kind,
+        } = self;
 
         hcx.with_node_id_hashing_mode(NodeIdHashingMode::Ignore, |hcx| {
             arguments.hash_stable(hcx, hasher);
             value.hash_stable(hcx, hasher);
-            is_generator.hash_stable(hcx, hasher);
+            generator_kind.hash_stable(hcx, hasher);
         });
     }
 }
diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs
index 4f618457d6c..9430661f75a 100644
--- a/src/librustc/ich/impls_syntax.rs
+++ b/src/librustc/ich/impls_syntax.rs
@@ -391,10 +391,17 @@ impl_stable_hash_for!(enum ::syntax::ast::MetaItemKind {
     NameValue(lit)
 });
 
+impl_stable_hash_for!(enum ::syntax_pos::hygiene::Transparency {
+    Transparent,
+    SemiTransparent,
+    Opaque,
+});
+
 impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnInfo {
     call_site,
-    def_site,
     format,
+    def_site,
+    default_transparency,
     allow_internal_unstable,
     allow_internal_unsafe,
     local_inner_macros,
diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs
index 383048b5fe7..3d57a89493e 100644
--- a/src/librustc/infer/canonical/canonicalizer.rs
+++ b/src/librustc/infer/canonical/canonicalizer.rs
@@ -14,7 +14,7 @@ use crate::mir::interpret::ConstValue;
 use std::sync::atomic::Ordering;
 use crate::ty::fold::{TypeFoldable, TypeFolder};
 use crate::ty::subst::Kind;
-use crate::ty::{self, BoundVar, InferConst, Lift, List, Ty, TyCtxt, TypeFlags};
+use crate::ty::{self, BoundVar, InferConst, List, Ty, TyCtxt, TypeFlags};
 use crate::ty::flags::FlagComputation;
 
 use rustc_data_structures::fx::FxHashMap;
@@ -43,7 +43,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
         query_state: &mut OriginalQueryValues<'tcx>,
     ) -> Canonicalized<'tcx, V>
     where
-        V: TypeFoldable<'tcx> + Lift<'tcx>,
+        V: TypeFoldable<'tcx>,
     {
         self.tcx
             .sess
@@ -87,7 +87,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
     /// [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html#canonicalizing-the-query-result
     pub fn canonicalize_response<V>(&self, value: &V) -> Canonicalized<'tcx, V>
     where
-        V: TypeFoldable<'tcx> + Lift<'tcx>,
+        V: TypeFoldable<'tcx>,
     {
         let mut query_state = OriginalQueryValues::default();
         Canonicalizer::canonicalize(
@@ -101,7 +101,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
 
     pub fn canonicalize_user_type_annotation<V>(&self, value: &V) -> Canonicalized<'tcx, V>
     where
-        V: TypeFoldable<'tcx> + Lift<'tcx>,
+        V: TypeFoldable<'tcx>,
     {
         let mut query_state = OriginalQueryValues::default();
         Canonicalizer::canonicalize(
@@ -132,7 +132,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
         query_state: &mut OriginalQueryValues<'tcx>,
     ) -> Canonicalized<'tcx, V>
     where
-        V: TypeFoldable<'tcx> + Lift<'tcx>,
+        V: TypeFoldable<'tcx>,
     {
         self.tcx
             .sess
@@ -506,7 +506,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
         query_state: &mut OriginalQueryValues<'tcx>,
     ) -> Canonicalized<'tcx, V>
     where
-        V: TypeFoldable<'tcx> + Lift<'tcx>,
+        V: TypeFoldable<'tcx>,
     {
         let needs_canonical_flags = if canonicalize_region_mode.any() {
             TypeFlags::KEEP_IN_LOCAL_TCX |
@@ -520,20 +520,12 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
             TypeFlags::HAS_CT_PLACEHOLDER
         };
 
-        let gcx = tcx.global_tcx();
-
         // Fast path: nothing that needs to be canonicalized.
         if !value.has_type_flags(needs_canonical_flags) {
-            let out_value = gcx.lift(value).unwrap_or_else(|| {
-                bug!(
-                    "failed to lift `{:?}` (nothing to canonicalize)",
-                    value
-                )
-            });
             let canon_value = Canonical {
                 max_universe: ty::UniverseIndex::ROOT,
                 variables: List::empty(),
-                value: out_value,
+                value: value.clone(),
             };
             return canon_value;
         }
@@ -553,13 +545,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
         // Once we have canonicalized `out_value`, it should not
         // contain anything that ties it to this inference context
         // anymore, so it should live in the global arena.
-        let out_value = gcx.lift(&out_value).unwrap_or_else(|| {
-            bug!(
-                "failed to lift `{:?}`, canonicalized from `{:?}`",
-                out_value,
-                value
-            )
-        });
+        debug_assert!(!out_value.has_type_flags(TypeFlags::KEEP_IN_LOCAL_TCX));
 
         let canonical_variables = tcx.intern_canonical_var_infos(&canonicalizer.variables);
 
diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs
index 8b1c34a487f..b2c7bd73b68 100644
--- a/src/librustc/infer/canonical/mod.rs
+++ b/src/librustc/infer/canonical/mod.rs
@@ -194,10 +194,10 @@ pub struct QueryResponse<'tcx, R> {
     pub value: R,
 }
 
-pub type Canonicalized<'tcx, V> = Canonical<'tcx, <V as Lift<'tcx>>::Lifted>;
+pub type Canonicalized<'tcx, V> = Canonical<'tcx, V>;
 
 pub type CanonicalizedQueryResponse<'tcx, T> =
-    &'tcx Canonical<'tcx, QueryResponse<'tcx, <T as Lift<'tcx>>::Lifted>>;
+    &'tcx Canonical<'tcx, QueryResponse<'tcx, T>>;
 
 /// Indicates whether or not we were able to prove the query to be
 /// true.
diff --git a/src/librustc/infer/canonical/query_response.rs b/src/librustc/infer/canonical/query_response.rs
index 8b11ebf9b92..3e92fed005c 100644
--- a/src/librustc/infer/canonical/query_response.rs
+++ b/src/librustc/infer/canonical/query_response.rs
@@ -26,7 +26,7 @@ use crate::traits::TraitEngine;
 use crate::traits::{Obligation, ObligationCause, PredicateObligation};
 use crate::ty::fold::TypeFoldable;
 use crate::ty::subst::{Kind, UnpackedKind};
-use crate::ty::{self, BoundVar, InferConst, Lift, Ty, TyCtxt};
+use crate::ty::{self, BoundVar, InferConst, Ty, TyCtxt};
 use crate::util::captures::Captures;
 
 impl<'tcx> InferCtxtBuilder<'tcx> {
@@ -53,8 +53,8 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
     ) -> Fallible<CanonicalizedQueryResponse<'tcx, R>>
     where
         K: TypeFoldable<'tcx>,
-        R: Debug + Lift<'tcx> + TypeFoldable<'tcx>,
-        Canonical<'tcx, <QueryResponse<'tcx, R> as Lift<'tcx>>::Lifted>: ArenaAllocatable,
+        R: Debug + TypeFoldable<'tcx>,
+        Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable,
     {
         self.enter_with_canonical(
             DUMMY_SP,
@@ -99,8 +99,8 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
         fulfill_cx: &mut dyn TraitEngine<'tcx>,
     ) -> Fallible<CanonicalizedQueryResponse<'tcx, T>>
     where
-        T: Debug + Lift<'tcx> + TypeFoldable<'tcx>,
-        Canonical<'tcx, <QueryResponse<'tcx, T> as Lift<'tcx>>::Lifted>: ArenaAllocatable,
+        T: Debug + TypeFoldable<'tcx>,
+        Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable,
     {
         let query_response = self.make_query_response(inference_vars, answer, fulfill_cx)?;
         let canonical_result = self.canonicalize_response(&query_response);
@@ -126,9 +126,9 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
         &self,
         inference_vars: CanonicalVarValues<'tcx>,
         answer: T,
-    ) -> Canonical<'tcx, QueryResponse<'tcx, <T as Lift<'tcx>>::Lifted>>
+    ) -> Canonical<'tcx, QueryResponse<'tcx, T>>
     where
-        T: Debug + Lift<'tcx> + TypeFoldable<'tcx>,
+        T: Debug + TypeFoldable<'tcx>,
     {
         self.canonicalize_response(&QueryResponse {
             var_values: inference_vars,
@@ -147,7 +147,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
         fulfill_cx: &mut dyn TraitEngine<'tcx>,
     ) -> Result<QueryResponse<'tcx, T>, NoSolution>
     where
-        T: Debug + TypeFoldable<'tcx> + Lift<'tcx>,
+        T: Debug + TypeFoldable<'tcx>,
     {
         let tcx = self.tcx;
 
diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs
index 362a680f53c..fe151bdec6a 100644
--- a/src/librustc/infer/error_reporting/need_type_info.rs
+++ b/src/librustc/infer/error_reporting/need_type_info.rs
@@ -227,16 +227,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
     pub fn need_type_info_err_in_generator(
         &self,
+        kind: hir::GeneratorKind,
         span: Span,
         ty: Ty<'tcx>,
     ) -> DiagnosticBuilder<'tcx> {
         let ty = self.resolve_vars_if_possible(&ty);
         let name = self.extract_type_name(&ty, None);
-
-        let mut err = struct_span_err!(self.tcx.sess,
-                       span,
-                       E0698,
-                       "type inside generator must be known in this context");
+        let mut err = struct_span_err!(
+            self.tcx.sess, span, E0698, "type inside {} must be known in this context", kind,
+        );
         err.span_label(span, InferCtxt::missing_type_msg(&name));
         err
     }
diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs
index c164f5446fd..60554a30060 100644
--- a/src/librustc/infer/opaque_types/mod.rs
+++ b/src/librustc/infer/opaque_types/mod.rs
@@ -469,11 +469,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             definition_ty
         );
 
-        // We can unwrap here because our reverse mapper always
-        // produces things with 'tcx lifetime, though the type folder
-        // obscures that.
-        let definition_ty = gcx.lift(&definition_ty).unwrap();
-
         definition_ty
     }
 }
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 1c3eead90fa..086ddfd7e33 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -546,7 +546,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
                 self.consume_expr(&base);
             }
 
-            hir::ExprKind::Yield(ref value) => {
+            hir::ExprKind::Yield(ref value, _) => {
                 self.consume_expr(&value);
             }
         }
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index dc6fa066071..bf054d68b70 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -1218,7 +1218,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
             hir::ExprKind::Type(ref e, _) |
             hir::ExprKind::DropTemps(ref e) |
             hir::ExprKind::Unary(_, ref e) |
-            hir::ExprKind::Yield(ref e) |
+            hir::ExprKind::Yield(ref e, _) |
             hir::ExprKind::Repeat(ref e, _) => {
                 self.propagate_through_expr(&e, succ)
             }
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 192e72383ac..c0f56a33eec 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -817,10 +817,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
                              .unwrap_or(ty::ClosureKind::LATTICE_BOTTOM),
 
                     None =>
-                        self.tcx.global_tcx()
-                                .lift(&closure_substs)
-                                .expect("no inference cx, but inference variables in closure ty")
-                                .closure_kind(closure_def_id, self.tcx.global_tcx()),
+                        closure_substs.closure_kind(closure_def_id, self.tcx.global_tcx()),
                 }
             }
             _ => span_bug!(span, "unexpected type for fn in mem_categorization: {:?}", ty),
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index dfab8e36bf9..93cb6ab96f8 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -331,7 +331,7 @@ pub struct ScopeTree {
     /// The reason is that semantically, until the `box` expression returns,
     /// the values are still owned by their containing expressions. So
     /// we'll see that `&x`.
-    yield_in_scope: FxHashMap<Scope, (Span, usize)>,
+    yield_in_scope: FxHashMap<Scope, YieldData>,
 
     /// The number of visit_expr and visit_pat calls done in the body.
     /// Used to sanity check visit_expr/visit_pat call count when
@@ -339,6 +339,15 @@ pub struct ScopeTree {
     body_expr_count: FxHashMap<hir::BodyId, usize>,
 }
 
+#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)]
+pub struct YieldData {
+    /// `Span` of the yield.
+    pub span: Span,
+    /// The number of expressions and patterns appearing before the `yield` in the body + 1.
+    pub expr_and_pat_count: usize,
+    pub source: hir::YieldSource,
+}
+
 #[derive(Debug, Copy, Clone)]
 pub struct Context {
     /// the root of the current region tree. This is typically the id
@@ -695,7 +704,7 @@ impl<'tcx> ScopeTree {
     /// returns `Some((span, expr_count))` with the span of a yield we found and
     /// the number of expressions and patterns appearing before the `yield` in the body + 1.
     /// If there a are multiple yields in a scope, the one with the highest number is returned.
-    pub fn yield_in_scope(&self, scope: Scope) -> Option<(Span, usize)> {
+    pub fn yield_in_scope(&self, scope: Scope) -> Option<YieldData> {
         self.yield_in_scope.get(&scope).cloned()
     }
 
@@ -706,14 +715,14 @@ impl<'tcx> ScopeTree {
                                    scope: Scope,
                                    expr_hir_id: hir::HirId,
                                    body: &'tcx hir::Body) -> Option<Span> {
-        self.yield_in_scope(scope).and_then(|(span, count)| {
+        self.yield_in_scope(scope).and_then(|YieldData { span, expr_and_pat_count, .. }| {
             let mut visitor = ExprLocatorVisitor {
                 hir_id: expr_hir_id,
                 result: None,
                 expr_and_pat_count: 0,
             };
             visitor.visit_body(body);
-            if count >= visitor.result.unwrap() {
+            if expr_and_pat_count >= visitor.result.unwrap() {
                 Some(span)
             } else {
                 None
@@ -953,12 +962,16 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
 
     debug!("resolve_expr post-increment {}, expr = {:?}", visitor.expr_and_pat_count, expr);
 
-    if let hir::ExprKind::Yield(..) = expr.node {
+    if let hir::ExprKind::Yield(_, source) = &expr.node {
         // Mark this expr's scope and all parent scopes as containing `yield`.
         let mut scope = Scope { id: expr.hir_id.local_id, data: ScopeData::Node };
         loop {
-            visitor.scope_tree.yield_in_scope.insert(scope,
-                (expr.span, visitor.expr_and_pat_count));
+            let data = YieldData {
+                span: expr.span,
+                expr_and_pat_count: visitor.expr_and_pat_count,
+                source: *source,
+            };
+            visitor.scope_tree.yield_in_scope.insert(scope, data);
 
             // Keep traversing up while we can.
             match visitor.scope_tree.parent_map.get(&scope) {
@@ -1302,7 +1315,7 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
             resolve_local(self, None, Some(&body.value));
         }
 
-        if body.is_generator {
+        if body.generator_kind.is_some() {
             self.scope_tree.body_expr_count.insert(body_id, self.expr_and_pat_count);
         }
 
diff --git a/src/librustc/traits/codegen/mod.rs b/src/librustc/traits/codegen/mod.rs
index bb4095333f1..97fb430a3e0 100644
--- a/src/librustc/traits/codegen/mod.rs
+++ b/src/librustc/traits/codegen/mod.rs
@@ -141,9 +141,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         &self,
         fulfill_cx: &mut FulfillmentContext<'tcx>,
         result: &T,
-    ) -> T::Lifted
+    ) -> T
     where
-        T: TypeFoldable<'tcx> + ty::Lift<'tcx>,
+        T: TypeFoldable<'tcx>,
     {
         debug!("drain_fulfillment_cx_or_panic()");
 
@@ -155,10 +155,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         }
 
         let result = self.resolve_vars_if_possible(result);
-        let result = self.tcx.erase_regions(&result);
-
-        self.tcx.lift_to_global(&result).unwrap_or_else(||
-            bug!("Uninferred types/regions/consts in `{:?}`", result)
-        )
+        self.tcx.erase_regions(&result)
     }
 }
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index 04364cd6311..0f4b7aff82b 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -409,7 +409,6 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
                             promoted: None
                         };
                         if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) {
-                            let substs = tcx.lift_to_global(&substs).unwrap();
                             let evaluated = evaluated.subst(tcx, substs);
                             return evaluated;
                         }
diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs
index a45213b06d3..5dd1b9e3d53 100644
--- a/src/librustc/traits/query/normalize.rs
+++ b/src/librustc/traits/query/normalize.rs
@@ -203,7 +203,6 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
                             promoted: None,
                         };
                         if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) {
-                            let substs = tcx.lift_to_global(&substs).unwrap();
                             let evaluated = evaluated.subst(tcx, substs);
                             return evaluated;
                         }
diff --git a/src/librustc/traits/query/type_op/mod.rs b/src/librustc/traits/query/type_op/mod.rs
index b298edfec59..4a07a3120f3 100644
--- a/src/librustc/traits/query/type_op/mod.rs
+++ b/src/librustc/traits/query/type_op/mod.rs
@@ -8,7 +8,7 @@ use std::rc::Rc;
 use crate::traits::query::Fallible;
 use crate::traits::ObligationCause;
 use crate::ty::fold::TypeFoldable;
-use crate::ty::{Lift, ParamEnvAnd, TyCtxt};
+use crate::ty::{ParamEnvAnd, TyCtxt};
 
 pub mod ascribe_user_type;
 pub mod custom;
@@ -44,8 +44,8 @@ pub trait TypeOp<'tcx>: Sized + fmt::Debug {
 /// which produces the resulting query region constraints.
 ///
 /// [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html
-pub trait QueryTypeOp<'tcx>: fmt::Debug + Sized + TypeFoldable<'tcx> + Lift<'tcx> {
-    type QueryResponse: TypeFoldable<'tcx> + Lift<'tcx>;
+pub trait QueryTypeOp<'tcx>: fmt::Debug + Sized + TypeFoldable<'tcx> + 'tcx {
+    type QueryResponse: TypeFoldable<'tcx>;
 
     /// Give query the option for a simple fast path that never
     /// actually hits the tcx cache lookup etc. Return `Some(r)` with
diff --git a/src/librustc/traits/query/type_op/normalize.rs b/src/librustc/traits/query/type_op/normalize.rs
index 5a768d9d58f..3fe85d8d83e 100644
--- a/src/librustc/traits/query/type_op/normalize.rs
+++ b/src/librustc/traits/query/type_op/normalize.rs
@@ -20,7 +20,7 @@ where
 
 impl<'tcx, T> super::QueryTypeOp<'tcx> for Normalize<T>
 where
-    T: Normalizable<'tcx>,
+    T: Normalizable<'tcx> + 'tcx,
 {
     type QueryResponse = T;
 
diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs
index 3d47e94fb00..43bb4edd9b2 100644
--- a/src/librustc/traits/specialize/mod.rs
+++ b/src/librustc/traits/specialize/mod.rs
@@ -132,12 +132,7 @@ pub fn find_associated_item<'tcx>(
                 let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
                 let substs = translate_substs(&infcx, param_env, impl_data.impl_def_id,
                                               substs, node_item.node);
-                let substs = infcx.tcx.erase_regions(&substs);
-                tcx.lift(&substs).unwrap_or_else(||
-                    bug!("find_method: translate_substs \
-                          returned {:?} which contains inference types/regions",
-                         substs)
-                )
+                infcx.tcx.erase_regions(&substs)
             });
             (node_item.item.def_id, substs)
         }
diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs
index d5e04500350..b8bdde4a787 100644
--- a/src/librustc/ty/error.rs
+++ b/src/librustc/ty/error.rs
@@ -192,9 +192,12 @@ impl<'tcx> ty::TyS<'tcx> {
 
             ty::Adt(def, _) => format!("{} `{}`", def.descr(), tcx.def_path_str(def.did)).into(),
             ty::Foreign(def_id) => format!("extern type `{}`", tcx.def_path_str(def_id)).into(),
-            ty::Array(_, n) => match n.assert_usize(tcx) {
-                Some(n) => format!("array of {} elements", n).into(),
-                None => "array".into(),
+            ty::Array(_, n) => {
+                let n = tcx.lift_to_global(&n).unwrap();
+                match n.assert_usize(tcx) {
+                    Some(n) => format!("array of {} elements", n).into(),
+                    None => "array".into(),
+                }
             }
             ty::Slice(_) => "slice".into(),
             ty::RawPtr(_) => "*-ptr".into(),
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 810a26d3736..8bfbd8b854b 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -2262,7 +2262,6 @@ impl<'tcx> Const<'tcx> {
 
     #[inline]
     pub fn from_bits(tcx: TyCtxt<'tcx>, bits: u128, ty: ParamEnvAnd<'tcx, Ty<'tcx>>) -> &'tcx Self {
-        let ty = tcx.lift_to_global(&ty).unwrap();
         let size = tcx.layout_of(ty).unwrap_or_else(|e| {
             panic!("could not compute layout for {:?}: {:?}", ty, e)
         }).size;
@@ -2289,7 +2288,6 @@ impl<'tcx> Const<'tcx> {
         if self.ty != ty.value {
             return None;
         }
-        let ty = tcx.lift_to_global(&ty).unwrap();
         let size = tcx.layout_of(ty).ok()?.size;
         self.val.try_to_bits(size)
     }
@@ -2300,15 +2298,14 @@ impl<'tcx> Const<'tcx> {
     }
 
     #[inline]
-    pub fn assert_bits(&self, tcx: TyCtxt<'_>, ty: ParamEnvAnd<'tcx, Ty<'tcx>>) -> Option<u128> {
+    pub fn assert_bits(&self, tcx: TyCtxt<'tcx>, ty: ParamEnvAnd<'tcx, Ty<'tcx>>) -> Option<u128> {
         assert_eq!(self.ty, ty.value);
-        let ty = tcx.lift_to_global(&ty).unwrap();
         let size = tcx.layout_of(ty).ok()?.size;
         self.val.try_to_bits(size)
     }
 
     #[inline]
-    pub fn assert_bool(&self, tcx: TyCtxt<'_>) -> Option<bool> {
+    pub fn assert_bool(&self, tcx: TyCtxt<'tcx>) -> Option<bool> {
         self.assert_bits(tcx, ParamEnv::empty().and(tcx.types.bool)).and_then(|v| match v {
             0 => Some(false),
             1 => Some(true),
@@ -2317,18 +2314,18 @@ impl<'tcx> Const<'tcx> {
     }
 
     #[inline]
-    pub fn assert_usize(&self, tcx: TyCtxt<'_>) -> Option<u64> {
+    pub fn assert_usize(&self, tcx: TyCtxt<'tcx>) -> Option<u64> {
         self.assert_bits(tcx, ParamEnv::empty().and(tcx.types.usize)).map(|v| v as u64)
     }
 
     #[inline]
-    pub fn unwrap_bits(&self, tcx: TyCtxt<'_>, ty: ParamEnvAnd<'tcx, Ty<'tcx>>) -> u128 {
+    pub fn unwrap_bits(&self, tcx: TyCtxt<'tcx>, ty: ParamEnvAnd<'tcx, Ty<'tcx>>) -> u128 {
         self.assert_bits(tcx, ty).unwrap_or_else(||
             bug!("expected bits of {}, got {:#?}", ty.value, self))
     }
 
     #[inline]
-    pub fn unwrap_usize(&self, tcx: TyCtxt<'_>) -> u64 {
+    pub fn unwrap_usize(&self, tcx: TyCtxt<'tcx>) -> u64 {
         self.assert_usize(tcx).unwrap_or_else(||
             bug!("expected constant usize, got {:#?}", self))
     }
diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs
index 3ec06b17aff..d402b0ddf6e 100644
--- a/src/librustc_allocator/expand.rs
+++ b/src/librustc_allocator/expand.rs
@@ -19,7 +19,7 @@ use syntax::{
     mut_visit::{self, MutVisitor},
     parse::ParseSess,
     ptr::P,
-    symbol::{kw, sym, Symbol}
+    symbol::{kw, sym}
 };
 use syntax_pos::Span;
 
@@ -58,11 +58,10 @@ impl MutVisitor for ExpandAllocatorDirectives<'_> {
     fn flat_map_item(&mut self, item: P<Item>) -> SmallVec<[P<Item>; 1]> {
         debug!("in submodule {}", self.in_submod);
 
-        let name = if attr::contains_name(&item.attrs, sym::global_allocator) {
-            "global_allocator"
-        } else {
+        if !attr::contains_name(&item.attrs, sym::global_allocator) {
             return mut_visit::noop_flat_map_item(item, self);
-        };
+        }
+
         match item.node {
             ItemKind::Static(..) => {}
             _ => {
@@ -87,15 +86,9 @@ impl MutVisitor for ExpandAllocatorDirectives<'_> {
 
         // Create a fresh Mark for the new macro expansion we are about to do
         let mark = Mark::fresh(Mark::root());
-        mark.set_expn_info(ExpnInfo {
-            call_site: item.span, // use the call site of the static
-            def_site: None,
-            format: MacroAttribute(Symbol::intern(name)),
-            allow_internal_unstable: Some(vec![sym::rustc_attrs].into()),
-            allow_internal_unsafe: false,
-            local_inner_macros: false,
-            edition: self.sess.edition,
-        });
+        mark.set_expn_info(ExpnInfo::with_unstable(
+            MacroAttribute(sym::global_allocator), item.span, self.sess.edition, &[sym::rustc_attrs]
+        ));
 
         // Tie the span to the macro expansion info we just created
         let span = item.span.with_ctxt(SyntaxContext::empty().apply_mark(mark));
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 6a01d7454be..df0957254cc 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -26,7 +26,7 @@ use std::{cmp, fs};
 
 use syntax::ast;
 use syntax::attr;
-use syntax::ext::base::SyntaxExtension;
+use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind};
 use syntax::symbol::{Symbol, sym};
 use syntax::visit;
 use syntax::{span_err, span_fatal};
@@ -611,33 +611,31 @@ impl<'a> CrateLoader<'a> {
         };
 
         let extensions = decls.iter().map(|&decl| {
-            match decl {
+            let (name, kind, helper_attrs) = match decl {
                 ProcMacro::CustomDerive { trait_name, attributes, client } => {
-                    let attrs = attributes.iter().cloned().map(Symbol::intern).collect::<Vec<_>>();
-                    (trait_name, SyntaxExtension::Derive(
-                        Box::new(ProcMacroDerive {
-                            client,
-                            attrs: attrs.clone(),
-                        }),
-                        attrs,
-                        root.edition,
-                    ))
+                    let helper_attrs =
+                        attributes.iter().cloned().map(Symbol::intern).collect::<Vec<_>>();
+                    (
+                        trait_name,
+                        SyntaxExtensionKind::Derive(Box::new(ProcMacroDerive {
+                            client, attrs: helper_attrs.clone()
+                        })),
+                        helper_attrs,
+                    )
                 }
-                ProcMacro::Attr { name, client } => {
-                    (name, SyntaxExtension::Attr(
-                        Box::new(AttrProcMacro { client }),
-                        root.edition,
-                    ))
-                }
-                ProcMacro::Bang { name, client } => {
-                    (name, SyntaxExtension::Bang {
-                        expander: Box::new(BangProcMacro { client }),
-                        allow_internal_unstable: None,
-                        edition: root.edition,
-                    })
-                }
-            }
-        }).map(|(name, ext)| (Symbol::intern(name), Lrc::new(ext))).collect();
+                ProcMacro::Attr { name, client } => (
+                    name, SyntaxExtensionKind::Attr(Box::new(AttrProcMacro { client })), Vec::new()
+                ),
+                ProcMacro::Bang { name, client } => (
+                    name, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })), Vec::new()
+                )
+            };
+
+            (Symbol::intern(name), Lrc::new(SyntaxExtension {
+                helper_attrs,
+                ..SyntaxExtension::default(kind, root.edition)
+            }))
+        }).collect();
 
         // Intentionally leak the dynamic library. We can't ever unload it
         // since the library can make things that will live arbitrarily long.
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 86536b179f2..04a9c4e9a1a 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -30,9 +30,11 @@ use syntax::ast;
 use syntax::attr;
 use syntax::source_map;
 use syntax::edition::Edition;
+use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind};
 use syntax::parse::source_file_to_stream;
 use syntax::parse::parser::emit_unclosed_delims;
 use syntax::symbol::{Symbol, sym};
+use syntax_ext::proc_macro_impl::BangProcMacro;
 use syntax_pos::{Span, NO_EXPANSION, FileName};
 use rustc_data_structures::bit_set::BitSet;
 
@@ -427,14 +429,11 @@ impl cstore::CStore {
         if let Some(ref proc_macros) = data.proc_macros {
             return LoadedMacro::ProcMacro(proc_macros[id.index.to_proc_macro_index()].1.clone());
         } else if data.name == sym::proc_macro && data.item_name(id.index) == sym::quote {
-            use syntax::ext::base::SyntaxExtension;
-            use syntax_ext::proc_macro_impl::BangProcMacro;
-
             let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote);
-            let ext = SyntaxExtension::Bang {
-                expander: Box::new(BangProcMacro { client }),
-                allow_internal_unstable: Some(vec![sym::proc_macro_def_site].into()),
-                edition: data.root.edition,
+            let kind = SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client }));
+            let ext = SyntaxExtension {
+                allow_internal_unstable: Some([sym::proc_macro_def_site][..].into()),
+                ..SyntaxExtension::default(kind, data.root.edition)
             };
             return LoadedMacro::ProcMacro(Lrc::new(ext));
         }
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index f78cc2f38a9..6a5f62aec15 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -509,8 +509,9 @@ impl<'a, 'tcx> CrateMetadata {
         if !self.is_proc_macro(index) {
             self.entry(index).kind.def_kind()
         } else {
-            let kind = self.proc_macros.as_ref().unwrap()[index.to_proc_macro_index()].1.kind();
-            Some(DefKind::Macro(kind))
+            Some(DefKind::Macro(
+                self.proc_macros.as_ref().unwrap()[index.to_proc_macro_index()].1.macro_kind()
+            ))
         }
     }
 
@@ -737,7 +738,7 @@ impl<'a, 'tcx> CrateMetadata {
             if id == CRATE_DEF_INDEX {
                 for (id, &(name, ref ext)) in proc_macros.iter().enumerate() {
                     let res = Res::Def(
-                        DefKind::Macro(ext.kind()),
+                        DefKind::Macro(ext.macro_kind()),
                         self.local_def_id(DefIndex::from_proc_macro_index(id)),
                     );
                     let ident = Ident::with_empty_ctxt(name);
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index afdc9f5c02a..ed56d351e90 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -670,7 +670,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx
                 // "Lift" into the gcx -- once regions are erased, this type should be in the
                 // global arenas; this "lift" operation basically just asserts that is true, but
                 // that is useful later.
-                let drop_place_ty = gcx.lift(&drop_place_ty).unwrap();
+                gcx.lift_to_global(&drop_place_ty).unwrap();
 
                 debug!("visit_terminator_drop \
                         loc: {:?} term: {:?} drop_place: {:?} drop_place_ty: {:?} span: {:?}",
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
index 2b38fcee479..41ed564d0f0 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
@@ -863,8 +863,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         });
         debug!("try_promote_type_test_subject: folded ty = {:?}", ty);
 
-        // `lift` will only fail if we failed to promote some region.
-        let ty = gcx.lift(&ty)?;
+        // `lift_to_global` will only fail if we failed to promote some region.
+        gcx.lift_to_global(&ty)?;
 
         Some(ClosureOutlivesSubject::Ty(ty))
     }
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index 16dfb161a54..e1f5964ff93 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -1864,7 +1864,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         // `Sized` bound in no way depends on precise regions, so this
         // shouldn't affect `is_sized`.
         let gcx = tcx.global_tcx();
-        let erased_ty = gcx.lift(&tcx.erase_regions(&ty)).unwrap();
+        let erased_ty = tcx.erase_regions(&ty);
         if !erased_ty.is_sized(gcx.at(span), self.param_env) {
             // in current MIR construction, all non-control-flow rvalue
             // expressions evaluate through `as_temp` or `into` a return
@@ -2650,7 +2650,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
 
     fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T
     where
-        T: type_op::normalize::Normalizable<'tcx> + Copy,
+        T: type_op::normalize::Normalizable<'tcx> + Copy + 'tcx,
     {
         debug!("normalize(value={:?}, location={:?})", value, location);
         let param_env = self.param_env;
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index 6d6e5de4761..243c13c2982 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -569,7 +569,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
     // Helper to get a `-1` value of the appropriate type
     fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
-        let param_ty = ty::ParamEnv::empty().and(self.hir.tcx().lift_to_global(&ty).unwrap());
+        let param_ty = ty::ParamEnv::empty().and(ty);
         let bits = self.hir.tcx().layout_of(param_ty).unwrap().size.bits();
         let n = (!0u128) >> (128 - bits);
         let literal = ty::Const::from_bits(self.hir.tcx(), n, param_ty);
@@ -580,7 +580,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     // Helper to get the minimum value of the appropriate type
     fn minval_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
         assert!(ty.is_signed());
-        let param_ty = ty::ParamEnv::empty().and(self.hir.tcx().lift_to_global(&ty).unwrap());
+        let param_ty = ty::ParamEnv::empty().and(ty);
         let bits = self.hir.tcx().layout_of(param_ty).unwrap().size.bits();
         let n = 1 << (bits - 1);
         let literal = ty::Const::from_bits(self.hir.tcx(), n, param_ty);
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 001f377c0ee..f7958434afa 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -126,7 +126,7 @@ pub fn mir_build<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Body<'tcx> {
 
             let arguments = implicit_argument.into_iter().chain(explicit_arguments);
 
-            let (yield_ty, return_ty) = if body.is_generator {
+            let (yield_ty, return_ty) = if body.generator_kind.is_some() {
                 let gen_sig = match ty.sty {
                     ty::Generator(gen_def_id, gen_substs, ..) =>
                         gen_substs.sig(gen_def_id, tcx),
@@ -590,7 +590,7 @@ where
         return_ty_span,
         upvar_debuginfo,
         upvar_mutbls,
-        body.is_generator);
+        body.generator_kind.is_some());
 
     let call_site_scope = region::Scope {
         id: body.value.hir_id.local_id,
diff --git a/src/librustc_mir/dataflow/drop_flag_effects.rs b/src/librustc_mir/dataflow/drop_flag_effects.rs
index e8a32477f1c..37f2a915782 100644
--- a/src/librustc_mir/dataflow/drop_flag_effects.rs
+++ b/src/librustc_mir/dataflow/drop_flag_effects.rs
@@ -151,7 +151,7 @@ pub(crate) fn on_all_drop_children_bits<'tcx, F>(
         debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, place, ty);
 
         let gcx = tcx.global_tcx();
-        let erased_ty = gcx.lift(&tcx.erase_regions(&ty)).unwrap();
+        let erased_ty = tcx.erase_regions(&ty);
         if erased_ty.needs_drop(gcx, ctxt.param_env) {
             each_child(child);
         } else {
diff --git a/src/librustc_mir/hair/constant.rs b/src/librustc_mir/hair/constant.rs
index 2cd04631118..bc01e3ee95b 100644
--- a/src/librustc_mir/hair/constant.rs
+++ b/src/librustc_mir/hair/constant.rs
@@ -18,7 +18,7 @@ crate fn lit_to_const<'tcx>(
     use syntax::ast::*;
 
     let trunc = |n| {
-        let param_ty = ParamEnv::reveal_all().and(tcx.lift_to_global(&ty).unwrap());
+        let param_ty = ParamEnv::reveal_all().and(ty);
         let width = tcx.layout_of(param_ty).map_err(|_| LitToConstError::Reported)?.size;
         trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
         let result = truncate(n, width);
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 9f05cf981f5..baf9086a480 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -763,7 +763,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
         hir::ExprKind::Array(ref fields) => ExprKind::Array { fields: fields.to_ref() },
         hir::ExprKind::Tup(ref fields) => ExprKind::Tuple { fields: fields.to_ref() },
 
-        hir::ExprKind::Yield(ref v) => ExprKind::Yield { value: v.to_ref() },
+        hir::ExprKind::Yield(ref v, _) => ExprKind::Yield { value: v.to_ref() },
         hir::ExprKind::Err => unreachable!(),
     };
 
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index fe54e2a0f18..4e197f1ed4e 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -190,12 +190,7 @@ impl<'a, 'tcx> Cx<'a, 'tcx> {
     }
 
     pub fn needs_drop(&mut self, ty: Ty<'tcx>) -> bool {
-        let (ty, param_env) = self.tcx.lift_to_global(&(ty, self.param_env)).unwrap_or_else(|| {
-            bug!("MIR: Cx::needs_drop({:?}, {:?}) got \
-                  type with inference types/regions",
-                 ty, self.param_env);
-        });
-        ty.needs_drop(self.tcx.global_tcx(), param_env)
+        ty.needs_drop(self.tcx.global_tcx(), self.param_env)
     }
 
     pub fn tcx(&self) -> TyCtxt<'tcx> {
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs
index 1fcdf713372..764ff0e15d5 100644
--- a/src/librustc_mir/hair/pattern/_match.rs
+++ b/src/librustc_mir/hair/pattern/_match.rs
@@ -1310,7 +1310,7 @@ fn is_useful_specialized<'p, 'a, 'tcx>(
 /// Returns `None` in case of a catch-all, which can't be specialized.
 fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt<'_, 'tcx>,
                           pat: &Pattern<'tcx>,
-                          pcx: PatternContext<'_>)
+                          pcx: PatternContext<'tcx>)
                           -> Option<Vec<Constructor<'tcx>>>
 {
     match *pat.kind {
diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs
index 1493d029048..bc1151974bb 100644
--- a/src/librustc_passes/rvalue_promotion.rs
+++ b/src/librustc_passes/rvalue_promotion.rs
@@ -545,7 +545,7 @@ fn check_expr_kind<'a, 'tcx>(
         }
 
         // Generator expressions
-        hir::ExprKind::Yield(ref expr) => {
+        hir::ExprKind::Yield(ref expr, _) => {
             let _ = v.check_expr(&expr);
             NotPromotable
         }
diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs
index dd5e42684c4..16d484e2a98 100644
--- a/src/librustc_plugin/registry.rs
+++ b/src/librustc_plugin/registry.rs
@@ -4,9 +4,8 @@ use rustc::lint::{EarlyLintPassObject, LateLintPassObject, LintId, Lint};
 use rustc::session::Session;
 use rustc::util::nodemap::FxHashMap;
 
-use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension};
+use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind, NamedSyntaxExtension};
 use syntax::ext::base::MacroExpanderFn;
-use syntax::ext::hygiene::Transparency;
 use syntax::symbol::{Symbol, sym};
 use syntax::ast;
 use syntax::feature_gate::AttributeType;
@@ -89,8 +88,8 @@ impl<'a> Registry<'a> {
         if name == sym::macro_rules {
             panic!("user-defined macros may not be named `macro_rules`");
         }
-        if let SyntaxExtension::LegacyBang { def_info: ref mut def_info @ None, .. } = extension {
-            *def_info = Some((ast::CRATE_NODE_ID, self.krate_span));
+        if extension.def_info.is_none() {
+            extension.def_info = Some((ast::CRATE_NODE_ID, self.krate_span));
         }
         self.syntax_exts.push((name, extension));
     }
@@ -98,19 +97,12 @@ impl<'a> Registry<'a> {
     /// Register a macro of the usual kind.
     ///
     /// This is a convenience wrapper for `register_syntax_extension`.
-    /// It builds for you a `SyntaxExtension::LegacyBang` that calls `expander`,
+    /// It builds for you a `SyntaxExtensionKind::LegacyBang` that calls `expander`,
     /// and also takes care of interning the macro's name.
     pub fn register_macro(&mut self, name: &str, expander: MacroExpanderFn) {
-        self.register_syntax_extension(Symbol::intern(name), SyntaxExtension::LegacyBang {
-            expander: Box::new(expander),
-            def_info: None,
-            transparency: Transparency::SemiTransparent,
-            allow_internal_unstable: None,
-            allow_internal_unsafe: false,
-            local_inner_macros: false,
-            unstable_feature: None,
-            edition: self.sess.edition(),
-        });
+        let kind = SyntaxExtensionKind::LegacyBang(Box::new(expander));
+        let ext = SyntaxExtension::default(kind, self.sess.edition());
+        self.register_syntax_extension(Symbol::intern(name), ext);
     }
 
     /// Register a compiler lint pass.
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 18ed91689ec..616728d5418 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -772,9 +772,8 @@ impl<'a> Resolver<'a> {
     pub fn get_macro(&mut self, res: Res) -> Lrc<SyntaxExtension> {
         let def_id = match res {
             Res::Def(DefKind::Macro(..), def_id) => def_id,
-            Res::NonMacroAttr(attr_kind) => return Lrc::new(SyntaxExtension::NonMacroAttr {
-                mark_used: attr_kind == NonMacroAttrKind::Tool,
-            }),
+            Res::NonMacroAttr(attr_kind) =>
+                return self.non_macro_attr(attr_kind == NonMacroAttrKind::Tool),
             _ => panic!("expected `DefKind::Macro` or `Res::NonMacroAttr`"),
         };
         if let Some(ext) = self.macro_map.get(&def_id) {
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index a127c960685..0fbd0666ad1 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -41,7 +41,7 @@ use rustc_metadata::cstore::CStore;
 use syntax::source_map::SourceMap;
 use syntax::ext::hygiene::{Mark, Transparency, SyntaxContext};
 use syntax::ast::{self, Name, NodeId, Ident, FloatTy, IntTy, UintTy};
-use syntax::ext::base::SyntaxExtension;
+use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind};
 use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
 use syntax::ext::base::MacroKind;
 use syntax::symbol::{Symbol, kw, sym};
@@ -1668,6 +1668,7 @@ pub struct Resolver<'a> {
     macro_use_prelude: FxHashMap<Name, &'a NameBinding<'a>>,
     pub all_macros: FxHashMap<Name, Res>,
     macro_map: FxHashMap<DefId, Lrc<SyntaxExtension>>,
+    non_macro_attrs: [Lrc<SyntaxExtension>; 2],
     macro_defs: FxHashMap<Mark, DefId>,
     local_macro_def_scopes: FxHashMap<NodeId, Module<'a>>,
 
@@ -1941,6 +1942,10 @@ impl<'a> Resolver<'a> {
         let mut macro_defs = FxHashMap::default();
         macro_defs.insert(Mark::root(), root_def_id);
 
+        let non_macro_attr = |mark_used| Lrc::new(SyntaxExtension::default(
+            SyntaxExtensionKind::NonMacroAttr { mark_used }, session.edition()
+        ));
+
         Resolver {
             session,
 
@@ -2014,6 +2019,7 @@ impl<'a> Resolver<'a> {
             macro_use_prelude: FxHashMap::default(),
             all_macros: FxHashMap::default(),
             macro_map: FxHashMap::default(),
+            non_macro_attrs: [non_macro_attr(false), non_macro_attr(true)],
             invocations,
             macro_defs,
             local_macro_def_scopes: FxHashMap::default(),
@@ -2030,6 +2036,10 @@ impl<'a> Resolver<'a> {
         Default::default()
     }
 
+    fn non_macro_attr(&self, mark_used: bool) -> Lrc<SyntaxExtension> {
+        self.non_macro_attrs[mark_used as usize].clone()
+    }
+
     /// Runs the function on each namespace.
     fn per_ns<F: FnMut(&mut Self, Namespace)>(&mut self, mut f: F) {
         f(self, TypeNS);
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 47ed3d684b2..5623016c2e5 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -114,6 +114,22 @@ fn sub_namespace_match(candidate: Option<MacroKind>, requirement: Option<MacroKi
     candidate.is_none() || requirement.is_none() || candidate == requirement
 }
 
+// We don't want to format a path using pretty-printing,
+// `format!("{}", path)`, because that tries to insert
+// line-breaks and is slow.
+fn fast_print_path(path: &ast::Path) -> String {
+    let mut path_str = String::with_capacity(64);
+    for (i, segment) in path.segments.iter().enumerate() {
+        if i != 0 {
+            path_str.push_str("::");
+        }
+        if segment.ident.name != kw::PathRoot {
+            path_str.push_str(&segment.ident.as_str())
+        }
+    }
+    path_str
+}
+
 impl<'a> base::Resolver for Resolver<'a> {
     fn next_node_id(&mut self) -> ast::NodeId {
         self.session.next_node_id()
@@ -174,7 +190,7 @@ impl<'a> base::Resolver for Resolver<'a> {
             krate: CrateNum::BuiltinMacros,
             index: DefIndex::from(self.macro_map.len()),
         };
-        let kind = ext.kind();
+        let kind = ext.macro_kind();
         self.macro_map.insert(def_id, ext);
         let binding = self.arenas.alloc_name_binding(NameBinding {
             kind: NameBindingKind::Res(Res::Def(DefKind::Macro(kind), def_id), false),
@@ -209,14 +225,19 @@ impl<'a> base::Resolver for Resolver<'a> {
         let parent_scope = self.invoc_parent_scope(invoc_id, derives_in_scope);
         let (res, ext) = match self.resolve_macro_to_res(path, kind, &parent_scope, true, force) {
             Ok((res, ext)) => (res, ext),
-            Err(Determinacy::Determined) if kind == MacroKind::Attr => {
-                // Replace unresolved attributes with used inert attributes for better recovery.
-                return Ok(Some(Lrc::new(SyntaxExtension::NonMacroAttr { mark_used: true })));
-            }
+            // Replace unresolved attributes with used inert attributes for better recovery.
+            Err(Determinacy::Determined) if kind == MacroKind::Attr =>
+                (Res::Err, self.non_macro_attr(true)),
             Err(determinacy) => return Err(determinacy),
         };
 
-        if let Res::Def(DefKind::Macro(_), def_id) = res {
+        let format = match kind {
+            MacroKind::Derive => format!("derive({})", fast_print_path(path)),
+            _ => fast_print_path(path),
+        };
+        invoc.expansion_data.mark.set_expn_info(ext.expn_info(invoc.span(), &format));
+
+        if let Res::Def(_, def_id) = res {
             if after_derive {
                 self.session.span_err(invoc.span(),
                                       "macro attributes must be placed before `#[derive]`");
@@ -226,7 +247,6 @@ impl<'a> base::Resolver for Resolver<'a> {
                 self.macro_def_scope(invoc.expansion_data.mark).normal_ancestor_id;
             self.definitions.add_parent_module_of_macro_def(invoc.expansion_data.mark,
                                                             normal_module_def_id);
-            invoc.expansion_data.mark.set_default_transparency(ext.default_transparency());
         }
 
         Ok(Some(ext))
@@ -241,11 +261,7 @@ impl<'a> base::Resolver for Resolver<'a> {
 
     fn check_unused_macros(&self) {
         for did in self.unused_macros.iter() {
-            let id_span = match *self.macro_map[did] {
-                SyntaxExtension::LegacyBang { def_info, .. } => def_info,
-                _ => None,
-            };
-            if let Some((id, span)) = id_span {
+            if let Some((id, span)) = self.macro_map[did].def_info {
                 let lint = lint::builtin::UNUSED_MACROS;
                 let msg = "unused macro definition";
                 self.session.buffer_lint(lint, id, span, msg);
@@ -585,17 +601,12 @@ impl<'a> Resolver<'a> {
                         let parent_scope = ParentScope { derives: Vec::new(), ..*parent_scope };
                         match self.resolve_macro_to_res(derive, MacroKind::Derive,
                                                         &parent_scope, true, force) {
-                            Ok((_, ext)) => {
-                                if let SyntaxExtension::Derive(_, helpers, _) = &*ext {
-                                    if helpers.contains(&ident.name) {
-                                        let binding =
-                                            (Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
-                                            ty::Visibility::Public, derive.span, Mark::root())
-                                            .to_name_binding(self.arenas);
-                                        result = Ok((binding, Flags::empty()));
-                                        break;
-                                    }
-                                }
+                            Ok((_, ext)) => if ext.helper_attrs.contains(&ident.name) {
+                                let binding = (Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
+                                               ty::Visibility::Public, derive.span, Mark::root())
+                                               .to_name_binding(self.arenas);
+                                result = Ok((binding, Flags::empty()));
+                                break;
                             }
                             Err(Determinacy::Determined) => {}
                             Err(Determinacy::Undetermined) =>
diff --git a/src/librustc_traits/normalize_erasing_regions.rs b/src/librustc_traits/normalize_erasing_regions.rs
index bfa1a80bb32..d138ce753b0 100644
--- a/src/librustc_traits/normalize_erasing_regions.rs
+++ b/src/librustc_traits/normalize_erasing_regions.rs
@@ -37,8 +37,7 @@ fn normalize_ty_after_erasing_regions<'tcx>(
                 );
 
                 let normalized_value = infcx.resolve_vars_if_possible(&normalized_value);
-                let normalized_value = infcx.tcx.erase_regions(&normalized_value);
-                tcx.lift_to_global(&normalized_value).unwrap()
+                infcx.tcx.erase_regions(&normalized_value)
             }
             Err(NoSolution) => bug!("could not fully normalize `{:?}`", value),
         }
diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index 421688097b8..563bb5760a9 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -295,7 +295,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ExprKind::Index(ref base, ref idx) => {
                 self.check_expr_index(base, idx, needs, expr)
             }
-            ExprKind::Yield(ref value) => {
+            ExprKind::Yield(ref value, _) => {
                 self.check_expr_yield(value, expr)
             }
             hir::ExprKind::Err => {
diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs
index ac2dcbadad8..72f42c85ead 100644
--- a/src/librustc_typeck/check/generator_interior.rs
+++ b/src/librustc_typeck/check/generator_interior.rs
@@ -6,7 +6,7 @@
 use rustc::hir::def_id::DefId;
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir::{self, Pat, PatKind, Expr};
-use rustc::middle::region;
+use rustc::middle::region::{self, YieldData};
 use rustc::ty::{self, Ty};
 use syntax_pos::Span;
 use super::FnCtxt;
@@ -17,6 +17,7 @@ struct InteriorVisitor<'a, 'tcx> {
     types: FxHashMap<Ty<'tcx>, usize>,
     region_scope_tree: &'tcx region::ScopeTree,
     expr_count: usize,
+    kind: hir::GeneratorKind,
 }
 
 impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
@@ -27,8 +28,8 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
               source_span: Span) {
         use syntax_pos::DUMMY_SP;
 
-        let live_across_yield = scope.map_or(Some(DUMMY_SP), |s| {
-            self.region_scope_tree.yield_in_scope(s).and_then(|(yield_span, expr_count)| {
+        let live_across_yield = scope.map(|s| {
+            self.region_scope_tree.yield_in_scope(s).and_then(|yield_data| {
                 // If we are recording an expression that is the last yield
                 // in the scope, or that has a postorder CFG index larger
                 // than the one of all of the yields, then its value can't
@@ -37,31 +38,43 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
                 // See the mega-comment at `yield_in_scope` for a proof.
 
                 debug!("comparing counts yield: {} self: {}, source_span = {:?}",
-                       expr_count, self.expr_count, source_span);
+                       yield_data.expr_and_pat_count, self.expr_count, source_span);
 
-                if expr_count >= self.expr_count {
-                    Some(yield_span)
+                if yield_data.expr_and_pat_count >= self.expr_count {
+                    Some(yield_data)
                 } else {
                     None
                 }
             })
-        });
-
-        if let Some(yield_span) = live_across_yield {
+        }).unwrap_or_else(|| Some(YieldData {
+            span: DUMMY_SP,
+            expr_and_pat_count: 0,
+            source: match self.kind { // Guess based on the kind of the current generator.
+                hir::GeneratorKind::Gen => hir::YieldSource::Yield,
+                hir::GeneratorKind::Async => hir::YieldSource::Await,
+            },
+        }));
+
+        if let Some(yield_data) = live_across_yield {
             let ty = self.fcx.resolve_vars_if_possible(&ty);
 
             debug!("type in expr = {:?}, scope = {:?}, type = {:?}, count = {}, yield_span = {:?}",
-                   expr, scope, ty, self.expr_count, yield_span);
+                   expr, scope, ty, self.expr_count, yield_data.span);
 
             if let Some((unresolved_type, unresolved_type_span)) =
                 self.fcx.unresolved_type_vars(&ty)
             {
+                let note = format!("the type is part of the {} because of this {}",
+                                   self.kind,
+                                   yield_data.source);
+
                 // If unresolved type isn't a ty_var then unresolved_type_span is None
                 self.fcx.need_type_info_err_in_generator(
-                    unresolved_type_span.unwrap_or(yield_span),
-                    unresolved_type)
-                    .span_note(yield_span,
-                               "the type is part of the generator because of this `yield`")
+                    self.kind,
+                    unresolved_type_span.unwrap_or(yield_data.span),
+                    unresolved_type,
+                )
+                    .span_note(yield_data.span, &*note)
                     .emit();
             } else {
                 // Map the type to the number of types added before it
@@ -80,6 +93,7 @@ pub fn resolve_interior<'a, 'tcx>(
     def_id: DefId,
     body_id: hir::BodyId,
     interior: Ty<'tcx>,
+    kind: hir::GeneratorKind,
 ) {
     let body = fcx.tcx.hir().body(body_id);
     let mut visitor = InteriorVisitor {
@@ -87,6 +101,7 @@ pub fn resolve_interior<'a, 'tcx>(
         types: FxHashMap::default(),
         region_scope_tree: fcx.tcx.region_scope_tree(def_id),
         expr_count: 0,
+        kind,
     };
     intravisit::walk_body(&mut visitor, body);
 
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 864f19933a5..177e2158044 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -217,7 +217,7 @@ pub struct Inherited<'a, 'tcx> {
 
     deferred_cast_checks: RefCell<Vec<cast::CastCheck<'tcx>>>,
 
-    deferred_generator_interiors: RefCell<Vec<(hir::BodyId, Ty<'tcx>)>>,
+    deferred_generator_interiors: RefCell<Vec<(hir::BodyId, Ty<'tcx>, hir::GeneratorKind)>>,
 
     // Opaque types found in explicit return types and their
     // associated fresh inference variable. Writeback resolves these
@@ -1071,7 +1071,7 @@ fn check_fn<'a, 'tcx>(
 
     let span = body.value.span;
 
-    if body.is_generator && can_be_generator.is_some() {
+    if body.generator_kind.is_some() && can_be_generator.is_some() {
         let yield_ty = fcx.next_ty_var(TypeVariableOrigin {
             kind: TypeVariableOriginKind::TypeInference,
             span,
@@ -1108,12 +1108,12 @@ fn check_fn<'a, 'tcx>(
     // We insert the deferred_generator_interiors entry after visiting the body.
     // This ensures that all nested generators appear before the entry of this generator.
     // resolve_generator_interiors relies on this property.
-    let gen_ty = if can_be_generator.is_some() && body.is_generator {
+    let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) {
         let interior = fcx.next_ty_var(TypeVariableOrigin {
             kind: TypeVariableOriginKind::MiscVariable,
             span,
         });
-        fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior));
+        fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind));
         Some(GeneratorTypes {
             yield_ty: fcx.yield_ty.unwrap(),
             interior,
@@ -1788,32 +1788,71 @@ fn check_packed_inner<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, stack: &mut Vec<De
     false
 }
 
+/// Emit an error when encountering more or less than one variant in a transparent enum.
+fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: &'tcx ty::AdtDef, sp: Span, did: DefId) {
+    let variant_spans: Vec<_> = adt.variants.iter().map(|variant| {
+        tcx.hir().span_if_local(variant.def_id).unwrap()
+    }).collect();
+    let msg = format!(
+        "needs exactly one variant, but has {}",
+        adt.variants.len(),
+    );
+    let mut err = struct_span_err!(tcx.sess, sp, E0731, "transparent enum {}", msg);
+    err.span_label(sp, &msg);
+    if let &[ref start.., ref end] = &variant_spans[..] {
+        for variant_span in start {
+            err.span_label(*variant_span, "");
+        }
+        err.span_label(*end, &format!("too many variants in `{}`", tcx.def_path_str(did)));
+    }
+    err.emit();
+}
+
+/// Emit an error when encountering more or less than one non-zero-sized field in a transparent
+/// enum.
+fn bad_non_zero_sized_fields<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    adt: &'tcx ty::AdtDef,
+    field_count: usize,
+    field_spans: impl Iterator<Item = Span>,
+    sp: Span,
+) {
+    let msg = format!("needs exactly one non-zero-sized field, but has {}", field_count);
+    let mut err = struct_span_err!(
+        tcx.sess,
+        sp,
+        E0690,
+        "{}transparent {} {}",
+        if adt.is_enum() { "the variant of a " } else { "" },
+        adt.descr(),
+        msg,
+    );
+    err.span_label(sp, &msg);
+    for sp in field_spans {
+        err.span_label(sp, "this field is non-zero-sized");
+    }
+    err.emit();
+}
+
 fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, def_id: DefId) {
     let adt = tcx.adt_def(def_id);
     if !adt.repr.transparent() {
         return;
     }
+    let sp = tcx.sess.source_map().def_span(sp);
 
     if adt.is_enum() {
         if !tcx.features().transparent_enums {
-            emit_feature_err(&tcx.sess.parse_sess,
-                             sym::transparent_enums,
-                             sp,
-                             GateIssue::Language,
-                             "transparent enums are unstable");
+            emit_feature_err(
+                &tcx.sess.parse_sess,
+                sym::transparent_enums,
+                sp,
+                GateIssue::Language,
+                "transparent enums are unstable",
+            );
         }
         if adt.variants.len() != 1 {
-            let variant_spans: Vec<_> = adt.variants.iter().map(|variant| {
-                tcx.hir().span_if_local(variant.def_id).unwrap()
-            }).collect();
-            let mut err = struct_span_err!(tcx.sess, sp, E0731,
-                            "transparent enum needs exactly one variant, but has {}",
-                            adt.variants.len());
-            if !variant_spans.is_empty() {
-                err.span_note(variant_spans, &format!("the following variants exist on `{}`",
-                                                      tcx.def_path_str(def_id)));
-            }
-            err.emit();
+            bad_variant_count(tcx, adt, sp, def_id);
             if adt.variants.is_empty() {
                 // Don't bother checking the fields. No variants (and thus no fields) exist.
                 return;
@@ -1841,28 +1880,24 @@ fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, def_id: DefId) {
         (span, zst, align1)
     });
 
-    let non_zst_fields = field_infos.clone().filter(|(_span, zst, _align1)| !*zst);
+    let non_zst_fields = field_infos.clone().filter_map(|(span, zst, _align1)| if !zst {
+        Some(span)
+    } else {
+        None
+    });
     let non_zst_count = non_zst_fields.clone().count();
     if non_zst_count != 1 {
-        let field_spans: Vec<_> = non_zst_fields.map(|(span, _zst, _align1)| span).collect();
-
-        let mut err = struct_span_err!(tcx.sess, sp, E0690,
-                         "{}transparent {} needs exactly one non-zero-sized field, but has {}",
-                         if adt.is_enum() { "the variant of a " } else { "" },
-                         adt.descr(),
-                         non_zst_count);
-        if !field_spans.is_empty() {
-            err.span_note(field_spans,
-                          &format!("the following non-zero-sized fields exist on `{}`:",
-                                   tcx.def_path_str(def_id)));
-        }
-        err.emit();
+        bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, sp);
     }
     for (span, zst, align1) in field_infos {
         if zst && !align1 {
-            span_err!(tcx.sess, span, E0691,
-                      "zero-sized field in transparent {} has alignment larger than 1",
-                      adt.descr());
+            struct_span_err!(
+                tcx.sess,
+                span,
+                E0691,
+                "zero-sized field in transparent {} has alignment larger than 1",
+                adt.descr(),
+            ).span_label(span, "has alignment larger than 1").emit();
         }
     }
 }
@@ -2598,9 +2633,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     fn resolve_generator_interiors(&self, def_id: DefId) {
         let mut generators = self.deferred_generator_interiors.borrow_mut();
-        for (body_id, interior) in generators.drain(..) {
+        for (body_id, interior, kind) in generators.drain(..) {
             self.select_obligations_where_possible(false);
-            generator_interior::resolve_interior(self, def_id, body_id, interior);
+            generator_interior::resolve_interior(self, def_id, body_id, interior, kind);
         }
     }
 
@@ -3922,52 +3957,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         Some(original_span.with_lo(original_span.hi() - BytePos(1)))
     }
 
-    // Rewrite `SelfCtor` to `Ctor`
-    pub fn rewrite_self_ctor(
-        &self,
-        res: Res,
-        span: Span,
-    ) -> Result<Res, ErrorReported> {
-        let tcx = self.tcx;
-        if let Res::SelfCtor(impl_def_id) = res {
-            let ty = self.impl_self_ty(span, impl_def_id).ty;
-            let adt_def = ty.ty_adt_def();
-
-            match adt_def {
-                Some(adt_def) if adt_def.has_ctor() => {
-                    let variant = adt_def.non_enum_variant();
-                    let ctor_def_id = variant.ctor_def_id.unwrap();
-                    Ok(Res::Def(DefKind::Ctor(CtorOf::Struct, variant.ctor_kind), ctor_def_id))
-                }
-                _ => {
-                    let mut err = tcx.sess.struct_span_err(span,
-                        "the `Self` constructor can only be used with tuple or unit structs");
-                    if let Some(adt_def) = adt_def {
-                        match adt_def.adt_kind() {
-                            AdtKind::Enum => {
-                                err.help("did you mean to use one of the enum's variants?");
-                            },
-                            AdtKind::Struct |
-                            AdtKind::Union => {
-                                err.span_suggestion(
-                                    span,
-                                    "use curly brackets",
-                                    String::from("Self { /* fields */ }"),
-                                    Applicability::HasPlaceholders,
-                                );
-                            }
-                        }
-                    }
-                    err.emit();
-
-                    Err(ErrorReported)
-                }
-            }
-        } else {
-            Ok(res)
-        }
-    }
-
     // Instantiates the given path, which must refer to an item with the given
     // number of type parameters and type.
     pub fn instantiate_value_path(&self,
@@ -3987,12 +3976,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let tcx = self.tcx;
 
-        let res = match self.rewrite_self_ctor(res, span) {
-            Ok(res) => res,
-            Err(ErrorReported) => return (tcx.types.err, res),
-        };
         let path_segs = match res {
-            Res::Local(_) => vec![],
+            Res::Local(_) | Res::SelfCtor(_) => vec![],
             Res::Def(kind, def_id) =>
                 AstConv::def_ids_for_value_path_segments(self, segments, self_ty, kind, def_id),
             _ => bug!("instantiate_value_path on {:?}", res),
@@ -4097,13 +4082,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             tcx.generics_of(*def_id).has_self
         }).unwrap_or(false);
 
+        let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res {
+            let ty = self.impl_self_ty(span, impl_def_id).ty;
+            let adt_def = ty.ty_adt_def();
+
+            match ty.sty {
+                ty::Adt(adt_def, substs) if adt_def.has_ctor() => {
+                    let variant = adt_def.non_enum_variant();
+                    let ctor_def_id = variant.ctor_def_id.unwrap();
+                    (
+                        Res::Def(DefKind::Ctor(CtorOf::Struct, variant.ctor_kind), ctor_def_id),
+                        Some(substs),
+                    )
+                }
+                _ => {
+                    let mut err = tcx.sess.struct_span_err(span,
+                        "the `Self` constructor can only be used with tuple or unit structs");
+                    if let Some(adt_def) = adt_def {
+                        match adt_def.adt_kind() {
+                            AdtKind::Enum => {
+                                err.help("did you mean to use one of the enum's variants?");
+                            },
+                            AdtKind::Struct |
+                            AdtKind::Union => {
+                                err.span_suggestion(
+                                    span,
+                                    "use curly brackets",
+                                    String::from("Self { /* fields */ }"),
+                                    Applicability::HasPlaceholders,
+                                );
+                            }
+                        }
+                    }
+                    err.emit();
+
+                    return (tcx.types.err, res)
+                }
+            }
+        } else {
+            (res, None)
+        };
         let def_id = res.def_id();
 
         // The things we are substituting into the type should not contain
         // escaping late-bound regions, and nor should the base type scheme.
         let ty = tcx.type_of(def_id);
 
-        let substs = AstConv::create_substs_for_generic_args(
+        let substs = self_ctor_substs.unwrap_or_else(|| AstConv::create_substs_for_generic_args(
             tcx,
             def_id,
             &[][..],
@@ -4173,7 +4198,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                 }
             },
-        );
+        ));
         assert!(!substs.has_escaping_bound_vars());
         assert!(!ty.has_escaping_bound_vars());
 
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index c14ae5932af..9259b3b5d3a 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -3,7 +3,7 @@
 use std::iter::once;
 
 use syntax::ast;
-use syntax::ext::base::{MacroKind, SyntaxExtension};
+use syntax::ext::base::MacroKind;
 use syntax::symbol::sym;
 use syntax_pos::Span;
 
@@ -470,18 +470,12 @@ fn build_macro(cx: &DocContext<'_>, did: DefId, name: ast::Name) -> clean::ItemE
             })
         }
         LoadedMacro::ProcMacro(ext) => {
-            let helpers = match &*ext {
-                &SyntaxExtension::Derive(_, ref syms, ..) => { syms.clean(cx) }
-                _ => Vec::new(),
-            };
-
             clean::ProcMacroItem(clean::ProcMacro {
-                kind: ext.kind(),
-                helpers,
+                kind: ext.macro_kind(),
+                helpers: ext.helper_attrs.clean(cx),
             })
         }
     }
-
 }
 
 /// A trait's generics clause actually contains all of the predicates for all of
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 36270682059..b42a78f1e22 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -3066,7 +3066,7 @@ fn render_implementor(cx: &Context, implementor: &Impl, w: &mut fmt::Formatter<'
         _ => false,
     };
     render_impl(w, cx, implementor, AssocItemLink::Anchor(None), RenderMode::Normal,
-                implementor.impl_item.stable_since(), false, Some(use_absolute), false)?;
+                implementor.impl_item.stable_since(), false, Some(use_absolute), false, false)?;
     Ok(())
 }
 
@@ -3077,7 +3077,7 @@ fn render_impls(cx: &Context, w: &mut fmt::Formatter<'_>,
         let did = i.trait_did().unwrap();
         let assoc_link = AssocItemLink::GotoSource(did, &i.inner_impl().provided_trait_methods);
         render_impl(w, cx, i, assoc_link,
-                    RenderMode::Normal, containing_item.stable_since(), true, None, false)?;
+                    RenderMode::Normal, containing_item.stable_since(), true, None, false, true)?;
     }
     Ok(())
 }
@@ -3307,7 +3307,7 @@ fn item_trait(
                 );
                 render_impl(w, cx, &implementor, assoc_link,
                             RenderMode::Normal, implementor.impl_item.stable_since(), false,
-                            None, true)?;
+                            None, true, false)?;
             }
             write_loading_content(w, "")?;
         }
@@ -3979,7 +3979,7 @@ fn render_assoc_items(w: &mut fmt::Formatter<'_>,
         };
         for i in &non_trait {
             render_impl(w, cx, i, AssocItemLink::Anchor(None), render_mode,
-                        containing_item.stable_since(), true, None, false)?;
+                        containing_item.stable_since(), true, None, false, true)?;
         }
     }
     if let AssocItemRender::DerefFor { .. } = what {
@@ -4161,7 +4161,8 @@ fn spotlight_decl(decl: &clean::FnDecl) -> Result<String, fmt::Error> {
 
 fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocItemLink<'_>,
                render_mode: RenderMode, outer_version: Option<&str>, show_def_docs: bool,
-               use_absolute: Option<bool>, is_on_foreign_type: bool) -> fmt::Result {
+               use_absolute: Option<bool>, is_on_foreign_type: bool,
+               show_default_items: bool) -> fmt::Result {
     if render_mode == RenderMode::Normal {
         let id = cx.derive_id(match i.inner_impl().trait_ {
             Some(ref t) => if is_on_foreign_type {
@@ -4345,9 +4346,13 @@ fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocIt
 
     // If we've implemented a trait, then also emit documentation for all
     // default items which weren't overridden in the implementation block.
-    if let Some(t) = trait_ {
-        render_default_items(w, cx, t, &i.inner_impl(),
-                             render_mode, outer_version, show_def_docs)?;
+    // We don't emit documentation for default items if they appear in the
+    // Implementations on Foreign Types or Implementors sections.
+    if show_default_items {
+        if let Some(t) = trait_ {
+            render_default_items(w, cx, t, &i.inner_impl(),
+                                render_mode, outer_version, show_def_docs)?;
+        }
     }
     write!(w, "</div>")?;
 
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 7fbfc3e1fc0..68b96a40829 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -423,7 +423,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
 
 /// Resolves a string as a macro.
 fn macro_resolve(cx: &DocContext<'_>, path_str: &str) -> Option<Res> {
-    use syntax::ext::base::{MacroKind, SyntaxExtension};
+    use syntax::ext::base::{MacroKind, SyntaxExtensionKind};
     let segment = ast::PathSegment::from_ident(Ident::from_str(path_str));
     let path = ast::Path { segments: vec![segment], span: DUMMY_SP };
     cx.enter_resolver(|resolver| {
@@ -433,7 +433,7 @@ fn macro_resolve(cx: &DocContext<'_>, path_str: &str) -> Option<Res> {
             if let Res::Def(DefKind::Macro(MacroKind::ProcMacroStub), _) = res {
                 // skip proc-macro stubs, they'll cause `get_macro` to crash
             } else {
-                if let SyntaxExtension::LegacyBang { .. } = *resolver.get_macro(res) {
+                if let SyntaxExtensionKind::LegacyBang(..) = resolver.get_macro(res).kind {
                     return Some(res.map_id(|_| panic!("unexpected id")));
                 }
             }
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 38b7dee40c4..318a5a3a82a 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -15,6 +15,7 @@ use crate::tokenstream::{self, TokenStream};
 use errors::{DiagnosticBuilder, DiagnosticId};
 use smallvec::{smallvec, SmallVec};
 use syntax_pos::{Span, MultiSpan, DUMMY_SP};
+use syntax_pos::hygiene::{ExpnInfo, ExpnFormat};
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::{self, Lrc};
@@ -548,37 +549,19 @@ impl MacroKind {
     }
 }
 
-/// An enum representing the different kinds of syntax extensions.
-pub enum SyntaxExtension {
+/// A syntax extension kind.
+pub enum SyntaxExtensionKind {
     /// A token-based function-like macro.
-    Bang {
+    Bang(
         /// An expander with signature TokenStream -> TokenStream.
-        expander: Box<dyn ProcMacro + sync::Sync + sync::Send>,
-        /// Whitelist of unstable features that are treated as stable inside this macro.
-        allow_internal_unstable: Option<Lrc<[Symbol]>>,
-        /// Edition of the crate in which this macro is defined.
-        edition: Edition,
-    },
+        Box<dyn ProcMacro + sync::Sync + sync::Send>,
+    ),
 
     /// An AST-based function-like macro.
-    LegacyBang {
+    LegacyBang(
         /// An expander with signature TokenStream -> AST.
-        expander: Box<dyn TTMacroExpander + sync::Sync + sync::Send>,
-        /// Some info about the macro's definition point.
-        def_info: Option<(ast::NodeId, Span)>,
-        /// Hygienic properties of identifiers produced by this macro.
-        transparency: Transparency,
-        /// Whitelist of unstable features that are treated as stable inside this macro.
-        allow_internal_unstable: Option<Lrc<[Symbol]>>,
-        /// Suppresses the `unsafe_code` lint for code produced by this macro.
-        allow_internal_unsafe: bool,
-        /// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro.
-        local_inner_macros: bool,
-        /// The macro's feature name and tracking issue number if it is unstable.
-        unstable_feature: Option<(Symbol, u32)>,
-        /// Edition of the crate in which this macro is defined.
-        edition: Edition,
-    },
+        Box<dyn TTMacroExpander + sync::Sync + sync::Send>,
+    ),
 
     /// A token-based attribute macro.
     Attr(
@@ -586,8 +569,6 @@ pub enum SyntaxExtension {
         /// The first TokenSteam is the attribute itself, the second is the annotated item.
         /// The produced TokenSteam replaces the input TokenSteam.
         Box<dyn AttrProcMacro + sync::Sync + sync::Send>,
-        /// Edition of the crate in which this macro is defined.
-        Edition,
     ),
 
     /// An AST-based attribute macro.
@@ -599,7 +580,8 @@ pub enum SyntaxExtension {
     ),
 
     /// A trivial attribute "macro" that does nothing,
-    /// only keeps the attribute and marks it as known.
+    /// only keeps the attribute and marks it as inert,
+    /// thus making it ineligible for further expansion.
     NonMacroAttr {
         /// Suppresses the `unused_attributes` lint for this attribute.
         mark_used: bool,
@@ -610,10 +592,6 @@ pub enum SyntaxExtension {
         /// An expander with signature TokenStream -> TokenStream (not yet).
         /// The produced TokenSteam is appended to the input TokenSteam.
         Box<dyn MultiItemModifier + sync::Sync + sync::Send>,
-        /// Names of helper attributes registered by this macro.
-        Vec<Symbol>,
-        /// Edition of the crate in which this macro is defined.
-        Edition,
     ),
 
     /// An AST-based derive macro.
@@ -624,42 +602,91 @@ pub enum SyntaxExtension {
     ),
 }
 
+/// A struct representing a macro definition in "lowered" form ready for expansion.
+pub struct SyntaxExtension {
+    /// A syntax extension kind.
+    pub kind: SyntaxExtensionKind,
+    /// Some info about the macro's definition point.
+    pub def_info: Option<(ast::NodeId, Span)>,
+    /// Hygienic properties of spans produced by this macro by default.
+    pub default_transparency: Transparency,
+    /// Whitelist of unstable features that are treated as stable inside this macro.
+    pub allow_internal_unstable: Option<Lrc<[Symbol]>>,
+    /// Suppresses the `unsafe_code` lint for code produced by this macro.
+    pub allow_internal_unsafe: bool,
+    /// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro.
+    pub local_inner_macros: bool,
+    /// The macro's feature name and tracking issue number if it is unstable.
+    pub unstable_feature: Option<(Symbol, u32)>,
+    /// Names of helper attributes registered by this macro.
+    pub helper_attrs: Vec<Symbol>,
+    /// Edition of the crate in which this macro is defined.
+    pub edition: Edition,
+}
+
+impl SyntaxExtensionKind {
+    /// When a syntax extension is constructed,
+    /// its transparency can often be inferred from its kind.
+    fn default_transparency(&self) -> Transparency {
+        match self {
+            SyntaxExtensionKind::Bang(..) |
+            SyntaxExtensionKind::Attr(..) |
+            SyntaxExtensionKind::Derive(..) |
+            SyntaxExtensionKind::NonMacroAttr { .. } => Transparency::Opaque,
+            SyntaxExtensionKind::LegacyBang(..) |
+            SyntaxExtensionKind::LegacyAttr(..) |
+            SyntaxExtensionKind::LegacyDerive(..) => Transparency::SemiTransparent,
+        }
+    }
+}
+
 impl SyntaxExtension {
     /// Returns which kind of macro calls this syntax extension.
-    pub fn kind(&self) -> MacroKind {
-        match *self {
-            SyntaxExtension::Bang { .. } |
-            SyntaxExtension::LegacyBang { .. } => MacroKind::Bang,
-            SyntaxExtension::Attr(..) |
-            SyntaxExtension::LegacyAttr(..) |
-            SyntaxExtension::NonMacroAttr { .. } => MacroKind::Attr,
-            SyntaxExtension::Derive(..) |
-            SyntaxExtension::LegacyDerive(..) => MacroKind::Derive,
+    pub fn macro_kind(&self) -> MacroKind {
+        match self.kind {
+            SyntaxExtensionKind::Bang(..) |
+            SyntaxExtensionKind::LegacyBang(..) => MacroKind::Bang,
+            SyntaxExtensionKind::Attr(..) |
+            SyntaxExtensionKind::LegacyAttr(..) |
+            SyntaxExtensionKind::NonMacroAttr { .. } => MacroKind::Attr,
+            SyntaxExtensionKind::Derive(..) |
+            SyntaxExtensionKind::LegacyDerive(..) => MacroKind::Derive,
         }
     }
 
-    pub fn default_transparency(&self) -> Transparency {
-        match *self {
-            SyntaxExtension::LegacyBang { transparency, .. } => transparency,
-            SyntaxExtension::Bang { .. } |
-            SyntaxExtension::Attr(..) |
-            SyntaxExtension::Derive(..) |
-            SyntaxExtension::NonMacroAttr { .. } => Transparency::Opaque,
-            SyntaxExtension::LegacyAttr(..) |
-            SyntaxExtension::LegacyDerive(..) => Transparency::SemiTransparent,
+    /// Constructs a syntax extension with default properties.
+    pub fn default(kind: SyntaxExtensionKind, edition: Edition) -> SyntaxExtension {
+        SyntaxExtension {
+            def_info: None,
+            default_transparency: kind.default_transparency(),
+            allow_internal_unstable: None,
+            allow_internal_unsafe: false,
+            local_inner_macros: false,
+            unstable_feature: None,
+            helper_attrs: Vec::new(),
+            edition,
+            kind,
         }
     }
 
-    pub fn edition(&self, default_edition: Edition) -> Edition {
-        match *self {
-            SyntaxExtension::Bang { edition, .. } |
-            SyntaxExtension::LegacyBang { edition, .. } |
-            SyntaxExtension::Attr(.., edition) |
-            SyntaxExtension::Derive(.., edition) => edition,
-            // Unstable legacy stuff
-            SyntaxExtension::NonMacroAttr { .. } |
-            SyntaxExtension::LegacyAttr(..) |
-            SyntaxExtension::LegacyDerive(..) => default_edition,
+    fn expn_format(&self, symbol: Symbol) -> ExpnFormat {
+        match self.kind {
+            SyntaxExtensionKind::Bang(..) |
+            SyntaxExtensionKind::LegacyBang(..) => ExpnFormat::MacroBang(symbol),
+            _ => ExpnFormat::MacroAttribute(symbol),
+        }
+    }
+
+    pub fn expn_info(&self, call_site: Span, format: &str) -> ExpnInfo {
+        ExpnInfo {
+            call_site,
+            format: self.expn_format(Symbol::intern(format)),
+            def_site: self.def_info.map(|(_, span)| span),
+            default_transparency: self.default_transparency,
+            allow_internal_unstable: self.allow_internal_unstable.clone(),
+            allow_internal_unsafe: self.allow_internal_unsafe,
+            local_inner_macros: self.local_inner_macros,
+            edition: self.edition,
         }
     }
 }
@@ -699,31 +726,6 @@ impl Determinacy {
     }
 }
 
-pub struct DummyResolver;
-
-impl Resolver for DummyResolver {
-    fn next_node_id(&mut self) -> ast::NodeId { ast::DUMMY_NODE_ID }
-
-    fn get_module_scope(&mut self, _id: ast::NodeId) -> Mark { Mark::root() }
-
-    fn resolve_dollar_crates(&mut self, _fragment: &AstFragment) {}
-    fn visit_ast_fragment_with_placeholders(&mut self, _invoc: Mark, _fragment: &AstFragment,
-                                            _derives: &[Mark]) {}
-    fn add_builtin(&mut self, _ident: ast::Ident, _ext: Lrc<SyntaxExtension>) {}
-
-    fn resolve_imports(&mut self) {}
-    fn resolve_macro_invocation(&mut self, _invoc: &Invocation, _invoc_id: Mark, _force: bool)
-                                -> Result<Option<Lrc<SyntaxExtension>>, Determinacy> {
-        Err(Determinacy::Determined)
-    }
-    fn resolve_macro_path(&mut self, _path: &ast::Path, _kind: MacroKind, _invoc_id: Mark,
-                          _derives_in_scope: Vec<ast::Path>, _force: bool)
-                          -> Result<Lrc<SyntaxExtension>, Determinacy> {
-        Err(Determinacy::Determined)
-    }
-    fn check_unused_macros(&self) {}
-}
-
 #[derive(Clone)]
 pub struct ModuleData {
     pub mod_path: Vec<ast::Ident>,
diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs
index a2cf4a2a82d..abc451c96ae 100644
--- a/src/libsyntax/ext/derive.rs
+++ b/src/libsyntax/ext/derive.rs
@@ -60,15 +60,10 @@ pub fn add_derived_markers<T>(cx: &mut ExtCtxt<'_>, span: Span, traits: &[ast::P
     }
     pretty_name.push(')');
 
-    cx.current_expansion.mark.set_expn_info(ExpnInfo {
-        call_site: span,
-        def_site: None,
-        format: ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)),
-        allow_internal_unstable: Some(vec![sym::rustc_attrs, sym::structural_match].into()),
-        allow_internal_unsafe: false,
-        local_inner_macros: false,
-        edition: cx.parse_sess.edition,
-    });
+    cx.current_expansion.mark.set_expn_info(ExpnInfo::with_unstable(
+        ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)), span, cx.parse_sess.edition,
+        &[sym::rustc_attrs, sym::structural_match],
+    ));
 
     let span = span.with_ctxt(cx.backtrace());
     item.visit_attrs(|attrs| {
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index d433e6c5a89..be90def0bdd 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -1,7 +1,7 @@
 use crate::ast::{self, Block, Ident, LitKind, NodeId, PatKind, Path};
 use crate::ast::{MacStmtStyle, StmtKind, ItemKind};
 use crate::attr::{self, HasAttrs};
-use crate::source_map::{ExpnInfo, MacroBang, MacroAttribute, dummy_spanned, respan};
+use crate::source_map::{dummy_spanned, respan};
 use crate::config::StripUnconfigured;
 use crate::ext::base::*;
 use crate::ext::derive::{add_derived_markers, collect_derives};
@@ -22,7 +22,6 @@ use crate::util::map_in_place::MapInPlace;
 use errors::{Applicability, FatalError};
 use smallvec::{smallvec, SmallVec};
 use syntax_pos::{Span, DUMMY_SP, FileName};
-use syntax_pos::hygiene::ExpnFormat;
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lrc;
@@ -189,23 +188,6 @@ impl AstFragmentKind {
     }
 }
 
-fn macro_bang_format(path: &ast::Path) -> ExpnFormat {
-    // We don't want to format a path using pretty-printing,
-    // `format!("{}", path)`, because that tries to insert
-    // line-breaks and is slow.
-    let mut path_str = String::with_capacity(64);
-    for (i, segment) in path.segments.iter().enumerate() {
-        if i != 0 {
-            path_str.push_str("::");
-        }
-        if segment.ident.name != kw::PathRoot {
-            path_str.push_str(&segment.ident.as_str())
-        }
-    }
-
-    MacroBang(Symbol::intern(&path_str))
-}
-
 pub struct Invocation {
     pub kind: InvocationKind,
     fragment_kind: AstFragmentKind,
@@ -388,8 +370,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                         derives.push(mark);
                         let item = match self.cx.resolver.resolve_macro_path(
                                 path, MacroKind::Derive, Mark::root(), Vec::new(), false) {
-                            Ok(ext) => match *ext {
-                                SyntaxExtension::LegacyDerive(..) => item_with_markers.clone(),
+                            Ok(ext) => match ext.kind {
+                                SyntaxExtensionKind::LegacyDerive(..) => item_with_markers.clone(),
                                 _ => item.clone(),
                             },
                             _ => item.clone(),
@@ -509,7 +491,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
     fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) -> Option<AstFragment> {
         if invoc.fragment_kind == AstFragmentKind::ForeignItems &&
            !self.cx.ecfg.macros_in_extern_enabled() {
-            if let SyntaxExtension::NonMacroAttr { .. } = *ext {} else {
+            if let SyntaxExtensionKind::NonMacroAttr { .. } = ext.kind {} else {
                 emit_feature_err(&self.cx.parse_sess, sym::macros_in_extern,
                                  invoc.span(), GateIssue::Language,
                                  "macro invocations in `extern {}` blocks are experimental");
@@ -548,34 +530,22 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             _ => unreachable!(),
         };
 
-        if let SyntaxExtension::NonMacroAttr { mark_used: false } = *ext {} else {
-            // Macro attrs are always used when expanded,
-            // non-macro attrs are considered used when the field says so.
-            attr::mark_used(&attr);
-        }
-        invoc.expansion_data.mark.set_expn_info(ExpnInfo {
-            call_site: attr.span,
-            def_site: None,
-            format: MacroAttribute(Symbol::intern(&attr.path.to_string())),
-            allow_internal_unstable: None,
-            allow_internal_unsafe: false,
-            local_inner_macros: false,
-            edition: ext.edition(self.cx.parse_sess.edition),
-        });
-
-        match *ext {
-            SyntaxExtension::NonMacroAttr { .. } => {
+        match &ext.kind {
+            SyntaxExtensionKind::NonMacroAttr { mark_used } => {
                 attr::mark_known(&attr);
+                if *mark_used {
+                    attr::mark_used(&attr);
+                }
                 item.visit_attrs(|attrs| attrs.push(attr));
                 Some(invoc.fragment_kind.expect_from_annotatables(iter::once(item)))
             }
-            SyntaxExtension::LegacyAttr(ref mac) => {
+            SyntaxExtensionKind::LegacyAttr(expander) => {
                 let meta = attr.parse_meta(self.cx.parse_sess)
                                .map_err(|mut e| { e.emit(); }).ok()?;
-                let item = mac.expand(self.cx, attr.span, &meta, item);
+                let item = expander.expand(self.cx, attr.span, &meta, item);
                 Some(invoc.fragment_kind.expect_from_annotatables(item))
             }
-            SyntaxExtension::Attr(ref mac, ..) => {
+            SyntaxExtensionKind::Attr(expander) => {
                 self.gate_proc_macro_attr_item(attr.span, &item);
                 let item_tok = TokenTree::token(token::Interpolated(Lrc::new(match item {
                     Annotatable::Item(item) => token::NtItem(item),
@@ -586,13 +556,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     Annotatable::Expr(expr) => token::NtExpr(expr),
                 })), DUMMY_SP).into();
                 let input = self.extract_proc_macro_attr_input(attr.tokens, attr.span);
-                let tok_result = mac.expand(self.cx, attr.span, input, item_tok);
+                let tok_result = expander.expand(self.cx, attr.span, input, item_tok);
                 let res = self.parse_ast_fragment(tok_result, invoc.fragment_kind,
                                                   &attr.path, attr.span);
                 self.gate_proc_macro_expansion(attr.span, &res);
                 res
             }
-            SyntaxExtension::Derive(..) | SyntaxExtension::LegacyDerive(..) => {
+            SyntaxExtensionKind::Derive(..) | SyntaxExtensionKind::LegacyDerive(..) => {
                 self.cx.span_err(attr.span, &format!("`{}` is a derive macro", attr.path));
                 self.cx.trace_macros_diag();
                 invoc.fragment_kind.dummy(attr.span)
@@ -693,7 +663,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                          invoc: Invocation,
                          ext: &SyntaxExtension)
                          -> Option<AstFragment> {
-        let (mark, kind) = (invoc.expansion_data.mark, invoc.fragment_kind);
+        let kind = invoc.fragment_kind;
         let (mac, ident, span) = match invoc.kind {
             InvocationKind::Bang { mac, ident, span } => (mac, ident, span),
             _ => unreachable!(),
@@ -701,21 +671,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         let path = &mac.node.path;
 
         let ident = ident.unwrap_or_else(|| Ident::invalid());
-        let validate_and_set_expn_info = |this: &mut Self, // arg instead of capture
-                                          def_site_span: Option<Span>,
-                                          allow_internal_unstable,
-                                          allow_internal_unsafe,
-                                          local_inner_macros,
-                                          // can't infer this type
-                                          unstable_feature: Option<(Symbol, u32)>,
-                                          edition| {
-
+        let validate = |this: &mut Self| {
             // feature-gate the macro invocation
-            if let Some((feature, issue)) = unstable_feature {
+            if let Some((feature, issue)) = ext.unstable_feature {
                 let crate_span = this.cx.current_expansion.crate_span.unwrap();
                 // don't stability-check macros in the same crate
                 // (the only time this is null is for syntax extensions registered as macros)
-                if def_site_span.map_or(false, |def_span| !crate_span.contains(def_span))
+                if ext.def_info.map_or(false, |(_, def_span)| !crate_span.contains(def_span))
                     && !span.allows_unstable(feature)
                     && this.cx.ecfg.features.map_or(true, |feats| {
                     // macro features will count as lib features
@@ -734,62 +696,39 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 this.cx.trace_macros_diag();
                 return Err(kind.dummy(span));
             }
-            mark.set_expn_info(ExpnInfo {
-                call_site: span,
-                def_site: def_site_span,
-                format: macro_bang_format(path),
-                allow_internal_unstable,
-                allow_internal_unsafe,
-                local_inner_macros,
-                edition,
-            });
             Ok(())
         };
 
-        let opt_expanded = match *ext {
-            SyntaxExtension::LegacyBang {
-                ref expander,
-                def_info,
-                ref allow_internal_unstable,
-                allow_internal_unsafe,
-                local_inner_macros,
-                unstable_feature,
-                edition,
-                ..
-            } => {
-                if let Err(dummy_span) = validate_and_set_expn_info(self, def_info.map(|(_, s)| s),
-                                                                    allow_internal_unstable.clone(),
-                                                                    allow_internal_unsafe,
-                                                                    local_inner_macros,
-                                                                    unstable_feature,
-                                                                    edition) {
+        let opt_expanded = match &ext.kind {
+            SyntaxExtensionKind::LegacyBang(expander) => {
+                if let Err(dummy_span) = validate(self) {
                     dummy_span
                 } else {
                     kind.make_from(expander.expand(
                         self.cx,
                         span,
                         mac.node.stream(),
-                        def_info.map(|(_, s)| s),
+                        ext.def_info.map(|(_, s)| s),
                     ))
                 }
             }
 
-            SyntaxExtension::Attr(..) |
-            SyntaxExtension::LegacyAttr(..) |
-            SyntaxExtension::NonMacroAttr { .. } => {
+            SyntaxExtensionKind::Attr(..) |
+            SyntaxExtensionKind::LegacyAttr(..) |
+            SyntaxExtensionKind::NonMacroAttr { .. } => {
                 self.cx.span_err(path.span,
                                  &format!("`{}` can only be used in attributes", path));
                 self.cx.trace_macros_diag();
                 kind.dummy(span)
             }
 
-            SyntaxExtension::Derive(..) | SyntaxExtension::LegacyDerive(..) => {
+            SyntaxExtensionKind::Derive(..) | SyntaxExtensionKind::LegacyDerive(..) => {
                 self.cx.span_err(path.span, &format!("`{}` is a derive macro", path));
                 self.cx.trace_macros_diag();
                 kind.dummy(span)
             }
 
-            SyntaxExtension::Bang { ref expander, ref allow_internal_unstable, edition } => {
+            SyntaxExtensionKind::Bang(expander) => {
                 if ident.name != kw::Invalid {
                     let msg =
                         format!("macro {}! expects no ident argument, given '{}'", path, ident);
@@ -798,19 +737,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     kind.dummy(span)
                 } else {
                     self.gate_proc_macro_expansion_kind(span, kind);
-                    invoc.expansion_data.mark.set_expn_info(ExpnInfo {
-                        call_site: span,
-                        // FIXME procedural macros do not have proper span info
-                        // yet, when they do, we should use it here.
-                        def_site: None,
-                        format: macro_bang_format(path),
-                        // FIXME probably want to follow macro_rules macros here.
-                        allow_internal_unstable: allow_internal_unstable.clone(),
-                        allow_internal_unsafe: false,
-                        local_inner_macros: false,
-                        edition,
-                    });
-
                     let tok_result = expander.expand(self.cx, span, mac.node.stream());
                     let result = self.parse_ast_fragment(tok_result, kind, path, span);
                     self.gate_proc_macro_expansion(span, &result);
@@ -867,55 +793,19 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             return None;
         }
 
-        let pretty_name = Symbol::intern(&format!("derive({})", path));
-        let span = path.span;
-        let attr = ast::Attribute {
-            path, span,
-            tokens: TokenStream::empty(),
-            // irrelevant:
-            id: ast::AttrId(0), style: ast::AttrStyle::Outer, is_sugared_doc: false,
-        };
-
-        let mut expn_info = ExpnInfo {
-            call_site: span,
-            def_site: None,
-            format: MacroAttribute(pretty_name),
-            allow_internal_unstable: None,
-            allow_internal_unsafe: false,
-            local_inner_macros: false,
-            edition: ext.edition(self.cx.parse_sess.edition),
-        };
-
-        match ext {
-            SyntaxExtension::Derive(expander, ..) | SyntaxExtension::LegacyDerive(expander) => {
-                let meta = match ext {
-                    SyntaxExtension::Derive(..) => ast::MetaItem { // FIXME(jseyfried) avoid this
-                        path: Path::from_ident(Ident::invalid()),
-                        span: DUMMY_SP,
-                        node: ast::MetaItemKind::Word,
-                    },
-                    _ => {
-                        expn_info.allow_internal_unstable = Some(vec![
-                            sym::rustc_attrs,
-                            Symbol::intern("derive_clone_copy"),
-                            Symbol::intern("derive_eq"),
-                            // RustcDeserialize and RustcSerialize
-                            Symbol::intern("libstd_sys_internals"),
-                        ].into());
-                        attr.meta()?
-                    }
-                };
-
-                invoc.expansion_data.mark.set_expn_info(expn_info);
-                let span = span.with_ctxt(self.cx.backtrace());
+        match &ext.kind {
+            SyntaxExtensionKind::Derive(expander) |
+            SyntaxExtensionKind::LegacyDerive(expander) => {
+                let meta = ast::MetaItem { node: ast::MetaItemKind::Word, span: path.span, path };
+                let span = meta.span.with_ctxt(self.cx.backtrace());
                 let items = expander.expand(self.cx, span, &meta, item);
                 Some(invoc.fragment_kind.expect_from_annotatables(items))
             }
             _ => {
-                let msg = &format!("macro `{}` may not be used for derive attributes", attr.path);
-                self.cx.span_err(span, msg);
+                let msg = &format!("macro `{}` may not be used for derive attributes", path);
+                self.cx.span_err(path.span, msg);
                 self.cx.trace_macros_diag();
-                invoc.fragment_kind.dummy(span)
+                invoc.fragment_kind.dummy(path.span)
             }
         }
     }
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index 22745a1a76d..7f051c260ec 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -1,6 +1,7 @@
 use crate::{ast, attr};
 use crate::edition::Edition;
-use crate::ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension, TTMacroExpander};
+use crate::ext::base::{SyntaxExtension, SyntaxExtensionKind};
+use crate::ext::base::{DummyResult, ExtCtxt, MacResult, TTMacroExpander};
 use crate::ext::expand::{AstFragment, AstFragmentKind};
 use crate::ext::hygiene::Transparency;
 use crate::ext::tt::macro_parser::{Success, Error, Failure};
@@ -376,7 +377,7 @@ pub fn compile(
         valid,
     });
 
-    let transparency = if attr::contains_name(&def.attrs, sym::rustc_transparent_macro) {
+    let default_transparency = if attr::contains_name(&def.attrs, sym::rustc_transparent_macro) {
         Transparency::Transparent
     } else if body.legacy {
         Transparency::SemiTransparent
@@ -426,14 +427,15 @@ pub fn compile(
         }
     });
 
-    SyntaxExtension::LegacyBang {
-        expander,
+    SyntaxExtension {
+        kind: SyntaxExtensionKind::LegacyBang(expander),
         def_info: Some((def.id, def.span)),
-        transparency,
+        default_transparency,
         allow_internal_unstable,
         allow_internal_unsafe,
         local_inner_macros,
         unstable_feature,
+        helper_attrs: Vec::new(),
         edition,
     }
 }
diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs
index eea94f0d194..6630bf90815 100644
--- a/src/libsyntax/std_inject.rs
+++ b/src/libsyntax/std_inject.rs
@@ -16,15 +16,9 @@ use syntax_pos::{DUMMY_SP, Span};
 /// The expanded code uses the unstable `#[prelude_import]` attribute.
 fn ignored_span(sp: Span, edition: Edition) -> Span {
     let mark = Mark::fresh(Mark::root());
-    mark.set_expn_info(ExpnInfo {
-        call_site: DUMMY_SP,
-        def_site: None,
-        format: MacroAttribute(Symbol::intern("std_inject")),
-        allow_internal_unstable: Some(vec![sym::prelude_import].into()),
-        allow_internal_unsafe: false,
-        local_inner_macros: false,
-        edition,
-    });
+    mark.set_expn_info(ExpnInfo::with_unstable(
+        MacroAttribute(Symbol::intern("std_inject")), sp, edition, &[sym::prelude_import]
+    ));
     sp.with_ctxt(SyntaxContext::empty().apply_mark(mark))
 }
 
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index cbaf12529c1..f90b76721ee 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -280,15 +280,10 @@ fn generate_test_harness(sess: &ParseSess,
         test_runner
     };
 
-    mark.set_expn_info(ExpnInfo {
-        call_site: DUMMY_SP,
-        def_site: None,
-        format: MacroAttribute(sym::test_case),
-        allow_internal_unstable: Some(vec![sym::main, sym::test, sym::rustc_attrs].into()),
-        allow_internal_unsafe: false,
-        local_inner_macros: false,
-        edition: sess.edition,
-    });
+    mark.set_expn_info(ExpnInfo::with_unstable(
+        MacroAttribute(sym::test_case), DUMMY_SP, sess.edition,
+        &[sym::main, sym::test, sym::rustc_attrs],
+    ));
 
     TestHarnessGenerator {
         cx,
diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs
index cf54eacc3d4..1fe6094fca6 100644
--- a/src/libsyntax_ext/deriving/mod.rs
+++ b/src/libsyntax_ext/deriving/mod.rs
@@ -2,9 +2,10 @@
 
 use rustc_data_structures::sync::Lrc;
 use syntax::ast::{self, MetaItem};
-use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension, Resolver, MultiItemModifier};
+use syntax::edition::Edition;
+use syntax::ext::base::{Annotatable, ExtCtxt, Resolver, MultiItemModifier};
+use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind};
 use syntax::ext::build::AstBuilder;
-use syntax::ext::hygiene::{Mark, SyntaxContext};
 use syntax::ptr::P;
 use syntax::symbol::{Symbol, sym};
 use syntax_pos::Span;
@@ -67,11 +68,25 @@ macro_rules! derive_traits {
             }
         }
 
-        pub fn register_builtin_derives(resolver: &mut dyn Resolver) {
+        pub fn register_builtin_derives(resolver: &mut dyn Resolver, edition: Edition) {
+            let allow_internal_unstable = Some([
+                sym::core_intrinsics,
+                sym::rustc_attrs,
+                Symbol::intern("derive_clone_copy"),
+                Symbol::intern("derive_eq"),
+                Symbol::intern("libstd_sys_internals"), // RustcDeserialize and RustcSerialize
+            ][..].into());
+
             $(
                 resolver.add_builtin(
                     ast::Ident::with_empty_ctxt(Symbol::intern($name)),
-                    Lrc::new(SyntaxExtension::LegacyDerive(Box::new(BuiltinDerive($func))))
+                    Lrc::new(SyntaxExtension {
+                        allow_internal_unstable: allow_internal_unstable.clone(),
+                        ..SyntaxExtension::default(
+                            SyntaxExtensionKind::LegacyDerive(Box::new(BuiltinDerive($func))),
+                            edition,
+                        )
+                    }),
                 );
             )*
         }
@@ -148,24 +163,11 @@ fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String {
 
 /// Constructs an expression that calls an intrinsic
 fn call_intrinsic(cx: &ExtCtxt<'_>,
-                  mut span: Span,
+                  span: Span,
                   intrinsic: &str,
                   args: Vec<P<ast::Expr>>)
                   -> P<ast::Expr> {
-    let intrinsic_allowed_via_allow_internal_unstable = cx
-        .current_expansion.mark.expn_info().unwrap()
-        .allow_internal_unstable.map_or(false, |features| features.iter().any(|&s|
-            s == sym::core_intrinsics
-        ));
-    if intrinsic_allowed_via_allow_internal_unstable {
-        span = span.with_ctxt(cx.backtrace());
-    } else { // Avoid instability errors with user defined curstom derives, cc #36316
-        let mut info = cx.current_expansion.mark.expn_info().unwrap();
-        info.allow_internal_unstable = Some(vec![sym::core_intrinsics].into());
-        let mark = Mark::fresh(Mark::root());
-        mark.set_expn_info(info);
-        span = span.with_ctxt(SyntaxContext::empty().apply_mark(mark));
-    }
+    let span = span.with_ctxt(cx.backtrace());
     let path = cx.std_path(&[sym::intrinsics, Symbol::intern(intrinsic)]);
     let call = cx.expr_call_global(span, path, args);
 
diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs
index 3dd17207cb8..b868f5b273c 100644
--- a/src/libsyntax_ext/lib.rs
+++ b/src/libsyntax_ext/lib.rs
@@ -43,32 +43,31 @@ pub mod proc_macro_impl;
 use rustc_data_structures::sync::Lrc;
 use syntax::ast;
 
-use syntax::ext::base::{MacroExpanderFn, NamedSyntaxExtension, SyntaxExtension};
-use syntax::ext::hygiene::Transparency;
+use syntax::ext::base::MacroExpanderFn;
+use syntax::ext::base::{NamedSyntaxExtension, SyntaxExtension, SyntaxExtensionKind};
 use syntax::edition::Edition;
 use syntax::symbol::{sym, Symbol};
 
 pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver,
                          user_exts: Vec<NamedSyntaxExtension>,
                          edition: Edition) {
-    deriving::register_builtin_derives(resolver);
+    deriving::register_builtin_derives(resolver, edition);
 
     let mut register = |name, ext| {
         resolver.add_builtin(ast::Ident::with_empty_ctxt(name), Lrc::new(ext));
     };
     macro_rules! register {
         ($( $name:ident: $f:expr, )*) => { $(
-            register(Symbol::intern(stringify!($name)),
-                     SyntaxExtension::LegacyBang {
-                        expander: Box::new($f as MacroExpanderFn),
-                        def_info: None,
-                        transparency: Transparency::SemiTransparent,
-                        allow_internal_unstable: None,
-                        allow_internal_unsafe: false,
-                        local_inner_macros: false,
-                        unstable_feature: None,
-                        edition,
-                    });
+            register(Symbol::intern(stringify!($name)), SyntaxExtension::default(
+                SyntaxExtensionKind::LegacyBang(Box::new($f as MacroExpanderFn)), edition
+            ));
+        )* }
+    }
+    macro_rules! register_attr {
+        ($( $name:ident: $f:expr, )*) => { $(
+            register(Symbol::intern(stringify!($name)), SyntaxExtension::default(
+                SyntaxExtensionKind::LegacyAttr(Box::new($f)), edition
+            ));
         )* }
     }
 
@@ -97,33 +96,26 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver,
         assert: assert::expand_assert,
     }
 
-    register(sym::test_case, SyntaxExtension::LegacyAttr(Box::new(test_case::expand)));
-    register(sym::test, SyntaxExtension::LegacyAttr(Box::new(test::expand_test)));
-    register(sym::bench, SyntaxExtension::LegacyAttr(Box::new(test::expand_bench)));
+    register_attr! {
+        test_case: test_case::expand,
+        test: test::expand_test,
+        bench: test::expand_bench,
+    }
 
     // format_args uses `unstable` things internally.
-    register(Symbol::intern("format_args"),
-             SyntaxExtension::LegacyBang {
-                expander: Box::new(format::expand_format_args),
-                def_info: None,
-                transparency: Transparency::SemiTransparent,
-                allow_internal_unstable: Some(vec![sym::fmt_internals].into()),
-                allow_internal_unsafe: false,
-                local_inner_macros: false,
-                unstable_feature: None,
-                edition,
-            });
-    register(sym::format_args_nl,
-             SyntaxExtension::LegacyBang {
-                 expander: Box::new(format::expand_format_args_nl),
-                 def_info: None,
-                 transparency: Transparency::SemiTransparent,
-                 allow_internal_unstable: Some(vec![sym::fmt_internals].into()),
-                 allow_internal_unsafe: false,
-                 local_inner_macros: false,
-                 unstable_feature: None,
-                 edition,
-             });
+    let allow_internal_unstable = Some([sym::fmt_internals][..].into());
+    register(Symbol::intern("format_args"), SyntaxExtension {
+        allow_internal_unstable: allow_internal_unstable.clone(),
+        ..SyntaxExtension::default(
+            SyntaxExtensionKind::LegacyBang(Box::new(format::expand_format_args)), edition
+        )
+    });
+    register(sym::format_args_nl, SyntaxExtension {
+        allow_internal_unstable,
+        ..SyntaxExtension::default(
+            SyntaxExtensionKind::LegacyBang(Box::new(format::expand_format_args_nl)), edition
+        )
+    });
 
     for (name, ext) in user_exts {
         register(name, ext);
diff --git a/src/libsyntax_ext/proc_macro_decls.rs b/src/libsyntax_ext/proc_macro_decls.rs
index 29297aa913e..45e65288a24 100644
--- a/src/libsyntax_ext/proc_macro_decls.rs
+++ b/src/libsyntax_ext/proc_macro_decls.rs
@@ -347,18 +347,10 @@ fn mk_decls(
     custom_macros: &[ProcMacroDef],
 ) -> P<ast::Item> {
     let mark = Mark::fresh(Mark::root());
-    mark.set_expn_info(ExpnInfo {
-        call_site: DUMMY_SP,
-        def_site: None,
-        format: MacroAttribute(sym::proc_macro),
-        allow_internal_unstable: Some(vec![
-            sym::rustc_attrs,
-            Symbol::intern("proc_macro_internals"),
-        ].into()),
-        allow_internal_unsafe: false,
-        local_inner_macros: false,
-        edition: cx.parse_sess.edition,
-    });
+    mark.set_expn_info(ExpnInfo::with_unstable(
+        MacroAttribute(sym::proc_macro), DUMMY_SP, cx.parse_sess.edition,
+        &[sym::rustc_attrs, Symbol::intern("proc_macro_internals")],
+    ));
     let span = DUMMY_SP.apply_mark(mark);
 
     let hidden = cx.meta_list_item_word(span, sym::hidden);
diff --git a/src/libsyntax_ext/test.rs b/src/libsyntax_ext/test.rs
index c20dc6cb2d7..24d3055e711 100644
--- a/src/libsyntax_ext/test.rs
+++ b/src/libsyntax_ext/test.rs
@@ -8,7 +8,7 @@ use syntax::attr;
 use syntax::ast;
 use syntax::print::pprust;
 use syntax::symbol::{Symbol, sym};
-use syntax_pos::{DUMMY_SP, Span};
+use syntax_pos::Span;
 use syntax::source_map::{ExpnInfo, MacroAttribute};
 use std::iter;
 
@@ -62,15 +62,10 @@ pub fn expand_test_or_bench(
 
     let (sp, attr_sp) = {
         let mark = Mark::fresh(Mark::root());
-        mark.set_expn_info(ExpnInfo {
-            call_site: DUMMY_SP,
-            def_site: None,
-            format: MacroAttribute(sym::test),
-            allow_internal_unstable: Some(vec![sym::rustc_attrs, sym::test].into()),
-            allow_internal_unsafe: false,
-            local_inner_macros: false,
-            edition: cx.parse_sess.edition,
-        });
+        mark.set_expn_info(ExpnInfo::with_unstable(
+            MacroAttribute(sym::test), attr_sp, cx.parse_sess.edition,
+            &[sym::rustc_attrs, sym::test],
+        ));
         (item.span.with_ctxt(SyntaxContext::empty().apply_mark(mark)),
          attr_sp.with_ctxt(SyntaxContext::empty().apply_mark(mark)))
     };
diff --git a/src/libsyntax_ext/test_case.rs b/src/libsyntax_ext/test_case.rs
index cffecdd0f18..6e3bc05b65e 100644
--- a/src/libsyntax_ext/test_case.rs
+++ b/src/libsyntax_ext/test_case.rs
@@ -15,7 +15,7 @@ use syntax::ext::hygiene::{Mark, SyntaxContext};
 use syntax::ast;
 use syntax::source_map::respan;
 use syntax::symbol::sym;
-use syntax_pos::{DUMMY_SP, Span};
+use syntax_pos::Span;
 use syntax::source_map::{ExpnInfo, MacroAttribute};
 use syntax::feature_gate;
 
@@ -37,15 +37,10 @@ pub fn expand(
 
     let sp = {
         let mark = Mark::fresh(Mark::root());
-        mark.set_expn_info(ExpnInfo {
-            call_site: DUMMY_SP,
-            def_site: None,
-            format: MacroAttribute(sym::test_case),
-            allow_internal_unstable: Some(vec![sym::test, sym::rustc_attrs].into()),
-            allow_internal_unsafe: false,
-            local_inner_macros: false,
-            edition: ecx.parse_sess.edition,
-        });
+        mark.set_expn_info(ExpnInfo::with_unstable(
+            MacroAttribute(sym::test_case), attr_sp, ecx.parse_sess.edition,
+            &[sym::test, sym::rustc_attrs],
+        ));
         attr_sp.with_ctxt(SyntaxContext::empty().apply_mark(mark))
     };
 
diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs
index b827416ab53..4dbd4ccda91 100644
--- a/src/libsyntax_pos/hygiene.rs
+++ b/src/libsyntax_pos/hygiene.rs
@@ -59,13 +59,12 @@ pub struct Mark(u32);
 #[derive(Clone, Debug)]
 struct MarkData {
     parent: Mark,
-    default_transparency: Transparency,
     expn_info: Option<ExpnInfo>,
 }
 
 /// A property of a macro expansion that determines how identifiers
 /// produced by that expansion are resolved.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub enum Transparency {
     /// Identifier produced by a transparent expansion is always resolved at call-site.
     /// Call-site spans in procedural macros, hygiene opt-out in `macro` should use this.
@@ -85,12 +84,7 @@ pub enum Transparency {
 impl Mark {
     pub fn fresh(parent: Mark) -> Self {
         HygieneData::with(|data| {
-            data.marks.push(MarkData {
-                parent,
-                // By default expansions behave like `macro_rules`.
-                default_transparency: Transparency::SemiTransparent,
-                expn_info: None,
-            });
+            data.marks.push(MarkData { parent, expn_info: None });
             Mark(data.marks.len() as u32 - 1)
         })
     }
@@ -118,7 +112,7 @@ impl Mark {
 
     #[inline]
     pub fn expn_info(self) -> Option<ExpnInfo> {
-        HygieneData::with(|data| data.expn_info(self))
+        HygieneData::with(|data| data.expn_info(self).cloned())
     }
 
     #[inline]
@@ -126,12 +120,6 @@ impl Mark {
         HygieneData::with(|data| data.marks[self.0 as usize].expn_info = Some(info))
     }
 
-    #[inline]
-    pub fn set_default_transparency(self, transparency: Transparency) {
-        assert_ne!(self, Mark::root());
-        HygieneData::with(|data| data.marks[self.0 as usize].default_transparency = transparency)
-    }
-
     pub fn is_descendant_of(self, ancestor: Mark) -> bool {
         HygieneData::with(|data| data.is_descendant_of(self, ancestor))
     }
@@ -172,9 +160,8 @@ impl Mark {
     #[inline]
     pub fn looks_like_proc_macro_derive(self) -> bool {
         HygieneData::with(|data| {
-            let mark_data = &data.marks[self.0 as usize];
-            if mark_data.default_transparency == Transparency::Opaque {
-                if let Some(expn_info) = &mark_data.expn_info {
+            if data.default_transparency(self) == Transparency::Opaque {
+                if let Some(expn_info) = &data.marks[self.0 as usize].expn_info {
                     if let ExpnFormat::MacroAttribute(name) = expn_info.format {
                         if name.as_str().starts_with("derive(") {
                             return true;
@@ -199,9 +186,6 @@ impl HygieneData {
         HygieneData {
             marks: vec![MarkData {
                 parent: Mark::root(),
-                // If the root is opaque, then loops searching for an opaque mark
-                // will automatically stop after reaching it.
-                default_transparency: Transparency::Opaque,
                 expn_info: None,
             }],
             syntax_contexts: vec![SyntaxContextData {
@@ -220,8 +204,8 @@ impl HygieneData {
         GLOBALS.with(|globals| f(&mut *globals.hygiene_data.borrow_mut()))
     }
 
-    fn expn_info(&self, mark: Mark) -> Option<ExpnInfo> {
-        self.marks[mark.0 as usize].expn_info.clone()
+    fn expn_info(&self, mark: Mark) -> Option<&ExpnInfo> {
+        self.marks[mark.0 as usize].expn_info.as_ref()
     }
 
     fn is_descendant_of(&self, mut mark: Mark, ancestor: Mark) -> bool {
@@ -235,7 +219,9 @@ impl HygieneData {
     }
 
     fn default_transparency(&self, mark: Mark) -> Transparency {
-        self.marks[mark.0 as usize].default_transparency
+        self.marks[mark.0 as usize].expn_info.as_ref().map_or(
+            Transparency::SemiTransparent, |einfo| einfo.default_transparency
+        )
     }
 
     fn modern(&self, ctxt: SyntaxContext) -> SyntaxContext {
@@ -427,7 +413,6 @@ impl SyntaxContext {
         HygieneData::with(|data| {
             data.marks.push(MarkData {
                 parent: Mark::root(),
-                default_transparency: Transparency::SemiTransparent,
                 expn_info: Some(expansion_info),
             });
 
@@ -613,7 +598,7 @@ impl SyntaxContext {
     /// `ctxt.outer().expn_info()`.
     #[inline]
     pub fn outer_expn_info(self) -> Option<ExpnInfo> {
-        HygieneData::with(|data| data.expn_info(data.outer(self)))
+        HygieneData::with(|data| data.expn_info(data.outer(self)).cloned())
     }
 
     /// `ctxt.outer_and_expn_info()` is equivalent to but faster than
@@ -622,7 +607,7 @@ impl SyntaxContext {
     pub fn outer_and_expn_info(self) -> (Mark, Option<ExpnInfo>) {
         HygieneData::with(|data| {
             let outer = data.outer(self);
-            (outer, data.expn_info(outer))
+            (outer, data.expn_info(outer).cloned())
         })
     }
 
@@ -651,6 +636,7 @@ impl fmt::Debug for SyntaxContext {
 /// Extra information for tracking spans of macro and syntax sugar expansion
 #[derive(Clone, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub struct ExpnInfo {
+    // --- The part unique to each expansion.
     /// The location of the actual macro invocation or syntax sugar , e.g.
     /// `let x = foo!();` or `if let Some(y) = x {}`
     ///
@@ -661,13 +647,18 @@ pub struct ExpnInfo {
     /// call_site span would have its own ExpnInfo, with the call_site
     /// pointing to the `foo!` invocation.
     pub call_site: Span,
+    /// The format with which the macro was invoked.
+    pub format: ExpnFormat,
+
+    // --- The part specific to the macro/desugaring definition.
+    // --- FIXME: Share it between expansions with the same definition.
     /// The span of the macro definition itself. The macro may not
     /// have a sensible definition span (e.g., something defined
     /// completely inside libsyntax) in which case this is None.
     /// This span serves only informational purpose and is not used for resolution.
     pub def_site: Option<Span>,
-    /// The format with which the macro was invoked.
-    pub format: ExpnFormat,
+    /// Transparency used by `apply_mark` for mark with this expansion info by default.
+    pub default_transparency: Transparency,
     /// List of #[unstable]/feature-gated features that the macro is allowed to use
     /// internally without forcing the whole crate to opt-in
     /// to them.
@@ -682,6 +673,30 @@ pub struct ExpnInfo {
     pub edition: Edition,
 }
 
+impl ExpnInfo {
+    /// Constructs an expansion info with default properties.
+    pub fn default(format: ExpnFormat, call_site: Span, edition: Edition) -> ExpnInfo {
+        ExpnInfo {
+            call_site,
+            format,
+            def_site: None,
+            default_transparency: Transparency::SemiTransparent,
+            allow_internal_unstable: None,
+            allow_internal_unsafe: false,
+            local_inner_macros: false,
+            edition,
+        }
+    }
+
+    pub fn with_unstable(format: ExpnFormat, call_site: Span, edition: Edition,
+                         allow_internal_unstable: &[Symbol]) -> ExpnInfo {
+        ExpnInfo {
+            allow_internal_unstable: Some(allow_internal_unstable.into()),
+            ..ExpnInfo::default(format, call_site, edition)
+        }
+    }
+}
+
 /// The source of expansion.
 #[derive(Clone, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
 pub enum ExpnFormat {
diff --git a/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs b/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs
index 330459fc08f..4cf8a4e33c5 100644
--- a/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs
@@ -11,8 +11,8 @@ extern crate rustc_plugin;
 use std::borrow::ToOwned;
 use syntax::ast;
 use syntax::ext::build::AstBuilder;
-use syntax::ext::base::{SyntaxExtension, TTMacroExpander, ExtCtxt, MacResult, MacEager};
-use syntax::ext::hygiene::Transparency;
+use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind};
+use syntax::ext::base::{TTMacroExpander, ExtCtxt, MacResult, MacEager};
 use syntax::print::pprust;
 use syntax::symbol::Symbol;
 use syntax_pos::Span;
@@ -38,15 +38,7 @@ impl TTMacroExpander for Expander {
 #[plugin_registrar]
 pub fn plugin_registrar(reg: &mut Registry) {
     let args = reg.args().to_owned();
-    reg.register_syntax_extension(Symbol::intern("plugin_args"),
-        SyntaxExtension::LegacyBang {
-            expander: Box::new(Expander { args: args, }),
-            def_info: None,
-            transparency: Transparency::SemiTransparent,
-            allow_internal_unstable: None,
-            allow_internal_unsafe: false,
-            local_inner_macros: false,
-            unstable_feature: None,
-            edition: reg.sess.edition(),
-        });
+    reg.register_syntax_extension(Symbol::intern("plugin_args"), SyntaxExtension::default(
+        SyntaxExtensionKind::LegacyBang(Box::new(Expander { args })), reg.sess.edition()
+    ));
 }
diff --git a/src/test/run-pass-fulldeps/myriad-closures.rs b/src/test/run-pass-fulldeps/myriad-closures.rs
index a1ea0e685d6..a6d3530f139 100644
--- a/src/test/run-pass-fulldeps/myriad-closures.rs
+++ b/src/test/run-pass-fulldeps/myriad-closures.rs
@@ -32,7 +32,7 @@ macro_rules! mk_fn {
 }
 
 fn main() {
-    // Make 2^12 functions, each containing 16 closures,
-    // resulting in 2^16 closures overall.
-    go_bacterial!(mk_fn 1 1 1 1  1 1 1 1  1 1 1 1);
+    // Make 2^8 functions, each containing 16 closures,
+    // resulting in 2^12 closures overall.
+    go_bacterial!(mk_fn 1 1 1 1  1 1 1 1);
 }
diff --git a/src/test/run-pass/ctfe/assoc-const.rs b/src/test/run-pass/consts/assoc-const.rs
index b70479d255b..b70479d255b 100644
--- a/src/test/run-pass/ctfe/assoc-const.rs
+++ b/src/test/run-pass/consts/assoc-const.rs
diff --git a/src/test/run-pass/ctfe/bswap-const.rs b/src/test/run-pass/consts/bswap-const.rs
index 3145c21acc9..3145c21acc9 100644
--- a/src/test/run-pass/ctfe/bswap-const.rs
+++ b/src/test/run-pass/consts/bswap-const.rs
diff --git a/src/test/run-pass/ctfe/chained-constants-stackoverflow.rs b/src/test/run-pass/consts/chained-constants-stackoverflow.rs
index a171567c5d2..a171567c5d2 100644
--- a/src/test/run-pass/ctfe/chained-constants-stackoverflow.rs
+++ b/src/test/run-pass/consts/chained-constants-stackoverflow.rs
diff --git a/src/test/run-pass/ctfe/const-block-non-item-statement-3.rs b/src/test/run-pass/consts/const-block-non-item-statement-3.rs
index 10a4c31f24e..10a4c31f24e 100644
--- a/src/test/run-pass/ctfe/const-block-non-item-statement-3.rs
+++ b/src/test/run-pass/consts/const-block-non-item-statement-3.rs
diff --git a/src/test/run-pass/ctfe/const-block-non-item-statement.rs b/src/test/run-pass/consts/const-block-non-item-statement.rs
index a1b9b586ad0..a1b9b586ad0 100644
--- a/src/test/run-pass/ctfe/const-block-non-item-statement.rs
+++ b/src/test/run-pass/consts/const-block-non-item-statement.rs
diff --git a/src/test/run-pass/ctfe/const-fn-type-name.rs b/src/test/run-pass/consts/const-fn-type-name.rs
index 2ee6415aa68..2ee6415aa68 100644
--- a/src/test/run-pass/ctfe/const-fn-type-name.rs
+++ b/src/test/run-pass/consts/const-fn-type-name.rs
diff --git a/src/test/run-pass/const-int-conversion.rs b/src/test/run-pass/consts/const-int-conversion.rs
index 1d3123d216e..1d3123d216e 100644
--- a/src/test/run-pass/const-int-conversion.rs
+++ b/src/test/run-pass/consts/const-int-conversion.rs
diff --git a/src/test/run-pass/const-int-overflowing.rs b/src/test/run-pass/consts/const-int-overflowing.rs
index 9597393df72..9597393df72 100644
--- a/src/test/run-pass/const-int-overflowing.rs
+++ b/src/test/run-pass/consts/const-int-overflowing.rs
diff --git a/src/test/run-pass/const-int-rotate.rs b/src/test/run-pass/consts/const-int-rotate.rs
index 16946eadd63..16946eadd63 100644
--- a/src/test/run-pass/const-int-rotate.rs
+++ b/src/test/run-pass/consts/const-int-rotate.rs
diff --git a/src/test/run-pass/const-int-saturating-arith.rs b/src/test/run-pass/consts/const-int-saturating-arith.rs
index dae4c7216b2..dae4c7216b2 100644
--- a/src/test/run-pass/const-int-saturating-arith.rs
+++ b/src/test/run-pass/consts/const-int-saturating-arith.rs
diff --git a/src/test/run-pass/const-int-sign.rs b/src/test/run-pass/consts/const-int-sign.rs
index fcd3ef4ea02..fcd3ef4ea02 100644
--- a/src/test/run-pass/const-int-sign.rs
+++ b/src/test/run-pass/consts/const-int-sign.rs
diff --git a/src/test/run-pass/const-int-wrapping.rs b/src/test/run-pass/consts/const-int-wrapping.rs
index db86c25194f..db86c25194f 100644
--- a/src/test/run-pass/const-int-wrapping.rs
+++ b/src/test/run-pass/consts/const-int-wrapping.rs
diff --git a/src/test/run-pass/const-needs_drop.rs b/src/test/run-pass/consts/const-needs_drop.rs
index 871300defaf..871300defaf 100644
--- a/src/test/run-pass/const-needs_drop.rs
+++ b/src/test/run-pass/consts/const-needs_drop.rs
diff --git a/src/test/run-pass/ctfe/deref_in_pattern.rs b/src/test/run-pass/consts/deref_in_pattern.rs
index cc47b5b49c0..cc47b5b49c0 100644
--- a/src/test/run-pass/ctfe/deref_in_pattern.rs
+++ b/src/test/run-pass/consts/deref_in_pattern.rs
diff --git a/src/test/run-pass/ctfe/ice-48279.rs b/src/test/run-pass/consts/ice-48279.rs
index d1d90df240c..d1d90df240c 100644
--- a/src/test/run-pass/ctfe/ice-48279.rs
+++ b/src/test/run-pass/consts/ice-48279.rs
diff --git a/src/test/run-pass/ctfe/issue-37550.rs b/src/test/run-pass/consts/issue-37550.rs
index 04865830df2..04865830df2 100644
--- a/src/test/run-pass/ctfe/issue-37550.rs
+++ b/src/test/run-pass/consts/issue-37550.rs
diff --git a/src/test/run-pass/ctfe/issue-broken-mir.rs b/src/test/run-pass/consts/issue-broken-mir.rs
index 36f0ff92104..36f0ff92104 100644
--- a/src/test/run-pass/ctfe/issue-broken-mir.rs
+++ b/src/test/run-pass/consts/issue-broken-mir.rs
diff --git a/src/test/run-pass/ctfe/locals-in-const-fn.rs b/src/test/run-pass/consts/locals-in-const-fn.rs
index 95d50171a84..95d50171a84 100644
--- a/src/test/run-pass/ctfe/locals-in-const-fn.rs
+++ b/src/test/run-pass/consts/locals-in-const-fn.rs
diff --git a/src/test/run-pass/ctfe/match-const-fn-structs.rs b/src/test/run-pass/consts/match-const-fn-structs.rs
index 5a68048c477..5a68048c477 100644
--- a/src/test/run-pass/ctfe/match-const-fn-structs.rs
+++ b/src/test/run-pass/consts/match-const-fn-structs.rs
diff --git a/src/test/run-pass/ctfe/mozjs-error.rs b/src/test/run-pass/consts/mozjs-error.rs
index 7edcadbf2cb..7edcadbf2cb 100644
--- a/src/test/run-pass/ctfe/mozjs-error.rs
+++ b/src/test/run-pass/consts/mozjs-error.rs
diff --git a/src/test/run-pass/ctfe/non-scalar-cast.rs b/src/test/run-pass/consts/non-scalar-cast.rs
index 671366c90ec..671366c90ec 100644
--- a/src/test/run-pass/ctfe/non-scalar-cast.rs
+++ b/src/test/run-pass/consts/non-scalar-cast.rs
diff --git a/src/test/run-pass/ctfe/promotion.rs b/src/test/run-pass/consts/promotion.rs
index 3c5401e4212..3c5401e4212 100644
--- a/src/test/run-pass/ctfe/promotion.rs
+++ b/src/test/run-pass/consts/promotion.rs
diff --git a/src/test/run-pass/ctfe/references.rs b/src/test/run-pass/consts/references.rs
index d0af47a8ea8..d0af47a8ea8 100644
--- a/src/test/run-pass/ctfe/references.rs
+++ b/src/test/run-pass/consts/references.rs
diff --git a/src/test/run-pass/ctfe/repeat_match.rs b/src/test/run-pass/consts/repeat_match.rs
index 20983184a47..20983184a47 100644
--- a/src/test/run-pass/ctfe/repeat_match.rs
+++ b/src/test/run-pass/consts/repeat_match.rs
diff --git a/src/test/run-pass/ctfe/return-in-const-fn.rs b/src/test/run-pass/consts/return-in-const-fn.rs
index 077a33c081b..077a33c081b 100644
--- a/src/test/run-pass/ctfe/return-in-const-fn.rs
+++ b/src/test/run-pass/consts/return-in-const-fn.rs
diff --git a/src/test/run-pass/ctfe/signed_enum_discr.rs b/src/test/run-pass/consts/signed_enum_discr.rs
index 2e4395ccf22..2e4395ccf22 100644
--- a/src/test/run-pass/ctfe/signed_enum_discr.rs
+++ b/src/test/run-pass/consts/signed_enum_discr.rs
diff --git a/src/test/run-pass/ctfe/transmute-const.rs b/src/test/run-pass/consts/transmute-const.rs
index e24f89cdffd..e24f89cdffd 100644
--- a/src/test/run-pass/ctfe/transmute-const.rs
+++ b/src/test/run-pass/consts/transmute-const.rs
diff --git a/src/test/run-pass/ctfe/tuple-struct-constructors.rs b/src/test/run-pass/consts/tuple-struct-constructors.rs
index 1655f0eb850..1655f0eb850 100644
--- a/src/test/run-pass/ctfe/tuple-struct-constructors.rs
+++ b/src/test/run-pass/consts/tuple-struct-constructors.rs
diff --git a/src/test/ui/async-await/unresolved_type_param.rs b/src/test/ui/async-await/unresolved_type_param.rs
index 77174b03217..578d41fe0df 100644
--- a/src/test/ui/async-await/unresolved_type_param.rs
+++ b/src/test/ui/async-await/unresolved_type_param.rs
@@ -7,9 +7,9 @@ async fn bar<T>() -> () {}
 
 async fn foo() {
     bar().await;
-    //~^ ERROR type inside generator must be known in this context
+    //~^ ERROR type inside `async` object must be known in this context
     //~| NOTE cannot infer type for `T`
-    //~| NOTE the type is part of the generator because of this `yield`
+    //~| NOTE the type is part of the `async` object because of this `await`
     //~| NOTE in this expansion of desugaring of `await`
 }
 fn main() {}
diff --git a/src/test/ui/async-await/unresolved_type_param.stderr b/src/test/ui/async-await/unresolved_type_param.stderr
index afb9adf4c77..f3090a2b980 100644
--- a/src/test/ui/async-await/unresolved_type_param.stderr
+++ b/src/test/ui/async-await/unresolved_type_param.stderr
@@ -1,10 +1,10 @@
-error[E0698]: type inside generator must be known in this context
+error[E0698]: type inside `async` object must be known in this context
   --> $DIR/unresolved_type_param.rs:9:5
    |
 LL |     bar().await;
    |     ^^^ cannot infer type for `T`
    |
-note: the type is part of the generator because of this `yield`
+note: the type is part of the `async` object because of this `await`
   --> $DIR/unresolved_type_param.rs:9:5
    |
 LL |     bar().await;
diff --git a/src/test/ui/feature-gates/feature-gate-transparent_enums.stderr b/src/test/ui/feature-gates/feature-gate-transparent_enums.stderr
index 4b22654e9e4..8ba079b89f5 100644
--- a/src/test/ui/feature-gates/feature-gate-transparent_enums.stderr
+++ b/src/test/ui/feature-gates/feature-gate-transparent_enums.stderr
@@ -1,10 +1,8 @@
 error[E0658]: transparent enums are unstable
   --> $DIR/feature-gate-transparent_enums.rs:2:1
    |
-LL | / enum OkButUnstableEnum {
-LL | |     Foo((), String, ()),
-LL | | }
-   | |_^
+LL | enum OkButUnstableEnum {
+   | ^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/60405
    = help: add #![feature(transparent_enums)] to the crate attributes to enable
diff --git a/src/test/ui/feature-gates/feature-gate-transparent_unions.stderr b/src/test/ui/feature-gates/feature-gate-transparent_unions.stderr
index 933b227de63..341324c3d67 100644
--- a/src/test/ui/feature-gates/feature-gate-transparent_unions.stderr
+++ b/src/test/ui/feature-gates/feature-gate-transparent_unions.stderr
@@ -1,11 +1,8 @@
 error[E0658]: transparent unions are unstable
   --> $DIR/feature-gate-transparent_unions.rs:2:1
    |
-LL | / union OkButUnstableUnion {
-LL | |     field: u8,
-LL | |     zst: (),
-LL | | }
-   | |_^
+LL | union OkButUnstableUnion {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/60405
    = help: add #![feature(transparent_unions)] to the crate attributes to enable
diff --git a/src/test/run-pass/issues/issue-57924.rs b/src/test/ui/issues/issue-57924.rs
index 232596334b0..dc2942225e3 100644
--- a/src/test/run-pass/issues/issue-57924.rs
+++ b/src/test/ui/issues/issue-57924.rs
@@ -3,6 +3,7 @@ pub struct Gcm<E>(E);
 impl<E> Gcm<E> {
     pub fn crash(e: E) -> Self {
         Self::<E>(e)
+        //~^ ERROR type arguments are not allowed for this type
     }
 }
 
diff --git a/src/test/ui/issues/issue-57924.stderr b/src/test/ui/issues/issue-57924.stderr
new file mode 100644
index 00000000000..2f184b1aae1
--- /dev/null
+++ b/src/test/ui/issues/issue-57924.stderr
@@ -0,0 +1,9 @@
+error[E0109]: type arguments are not allowed for this type
+  --> $DIR/issue-57924.rs:5:16
+   |
+LL |         Self::<E>(e)
+   |                ^ type argument not allowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0109`.
diff --git a/src/test/ui/issues/issue-61882-2.rs b/src/test/ui/issues/issue-61882-2.rs
new file mode 100644
index 00000000000..1209b54bc41
--- /dev/null
+++ b/src/test/ui/issues/issue-61882-2.rs
@@ -0,0 +1,11 @@
+struct A<T>(T);
+
+impl A<&'static u8> {
+    fn f() {
+        let x = 0;
+        Self(&x);
+        //~^ ERROR `x` does not live long enough
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-61882-2.stderr b/src/test/ui/issues/issue-61882-2.stderr
new file mode 100644
index 00000000000..03a65540ced
--- /dev/null
+++ b/src/test/ui/issues/issue-61882-2.stderr
@@ -0,0 +1,15 @@
+error[E0597]: `x` does not live long enough
+  --> $DIR/issue-61882-2.rs:6:14
+   |
+LL |         Self(&x);
+   |              ^^
+   |              |
+   |              borrowed value does not live long enough
+   |              requires that `x` is borrowed for `'static`
+LL |
+LL |     }
+   |     - `x` dropped here while still borrowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/issues/issue-61882.rs b/src/test/ui/issues/issue-61882.rs
new file mode 100644
index 00000000000..013398b4598
--- /dev/null
+++ b/src/test/ui/issues/issue-61882.rs
@@ -0,0 +1,9 @@
+struct A<T>(T);
+
+impl A<bool> {
+    const B: A<u8> = Self(0);
+    //~^ ERROR mismatched types
+    //~| ERROR mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-61882.stderr b/src/test/ui/issues/issue-61882.stderr
new file mode 100644
index 00000000000..a14e1a4dd4d
--- /dev/null
+++ b/src/test/ui/issues/issue-61882.stderr
@@ -0,0 +1,21 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-61882.rs:4:27
+   |
+LL |     const B: A<u8> = Self(0);
+   |                           ^ expected bool, found integer
+   |
+   = note: expected type `bool`
+              found type `{integer}`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-61882.rs:4:22
+   |
+LL |     const B: A<u8> = Self(0);
+   |                      ^^^^^^^ expected u8, found bool
+   |
+   = note: expected type `A<u8>`
+              found type `A<bool>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/repr/repr-transparent.stderr b/src/test/ui/repr/repr-transparent.stderr
index ea16bdf5378..f0c1fbe8ac9 100644
--- a/src/test/ui/repr/repr-transparent.stderr
+++ b/src/test/ui/repr/repr-transparent.stderr
@@ -2,61 +2,57 @@ error[E0690]: transparent struct needs exactly one non-zero-sized field, but has
   --> $DIR/repr-transparent.rs:11:1
    |
 LL | struct NoFields;
-   | ^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 0
 
 error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 0
   --> $DIR/repr-transparent.rs:14:1
    |
 LL | struct ContainsOnlyZst(());
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 0
 
 error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 0
   --> $DIR/repr-transparent.rs:17:1
    |
 LL | struct ContainsOnlyZstArray([bool; 0]);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 0
 
 error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 0
   --> $DIR/repr-transparent.rs:20:1
    |
 LL | struct ContainsMultipleZst(PhantomData<*const i32>, NoFields);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 0
 
 error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 2
   --> $DIR/repr-transparent.rs:24:1
    |
 LL | struct MultipleNonZst(u8, u8);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: the following non-zero-sized fields exist on `MultipleNonZst`:
-  --> $DIR/repr-transparent.rs:24:23
-   |
-LL | struct MultipleNonZst(u8, u8);
-   |                       ^^  ^^
+   | ^^^^^^^^^^^^^^^^^^^^^^--^^--^^
+   | |                     |   |
+   | |                     |   this field is non-zero-sized
+   | |                     this field is non-zero-sized
+   | needs exactly one non-zero-sized field, but has 2
 
 error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 2
   --> $DIR/repr-transparent.rs:30:1
    |
 LL | pub struct StructWithProjection(f32, <f32 as Mirror>::It);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: the following non-zero-sized fields exist on `StructWithProjection`:
-  --> $DIR/repr-transparent.rs:30:33
-   |
-LL | pub struct StructWithProjection(f32, <f32 as Mirror>::It);
-   |                                 ^^^  ^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---^^-------------------^^
+   | |                               |    |
+   | |                               |    this field is non-zero-sized
+   | |                               this field is non-zero-sized
+   | needs exactly one non-zero-sized field, but has 2
 
 error[E0691]: zero-sized field in transparent struct has alignment larger than 1
   --> $DIR/repr-transparent.rs:34:32
    |
 LL | struct NontrivialAlignZst(u32, [u16; 0]);
-   |                                ^^^^^^^^
+   |                                ^^^^^^^^ has alignment larger than 1
 
 error[E0691]: zero-sized field in transparent struct has alignment larger than 1
   --> $DIR/repr-transparent.rs:40:24
    |
 LL | struct GenericAlign<T>(ZstAlign32<T>, u32);
-   |                        ^^^^^^^^^^^^^
+   |                        ^^^^^^^^^^^^^ has alignment larger than 1
 
 error[E0084]: unsupported representation for zero-variant enum
   --> $DIR/repr-transparent.rs:42:1
@@ -70,71 +66,49 @@ error[E0731]: transparent enum needs exactly one variant, but has 0
   --> $DIR/repr-transparent.rs:43:1
    |
 LL | enum Void {}
-   | ^^^^^^^^^^^^
+   | ^^^^^^^^^ needs exactly one variant, but has 0
 
 error[E0690]: the variant of a transparent enum needs exactly one non-zero-sized field, but has 0
   --> $DIR/repr-transparent.rs:47:1
    |
-LL | / enum FieldlessEnum {
-LL | |     Foo,
-LL | | }
-   | |_^
+LL | enum FieldlessEnum {
+   | ^^^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 0
 
 error[E0690]: the variant of a transparent enum needs exactly one non-zero-sized field, but has 2
   --> $DIR/repr-transparent.rs:52:1
    |
-LL | / enum TooManyFieldsEnum {
-LL | |     Foo(u32, String),
-LL | | }
-   | |_^
-   |
-note: the following non-zero-sized fields exist on `TooManyFieldsEnum`:
-  --> $DIR/repr-transparent.rs:53:9
-   |
+LL | enum TooManyFieldsEnum {
+   | ^^^^^^^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 2
 LL |     Foo(u32, String),
-   |         ^^^  ^^^^^^
+   |         ---  ------ this field is non-zero-sized
+   |         |
+   |         this field is non-zero-sized
 
 error[E0731]: transparent enum needs exactly one variant, but has 2
   --> $DIR/repr-transparent.rs:58:1
    |
-LL | / enum TooManyVariants {
-LL | |     Foo(String),
-LL | |     Bar,
-LL | | }
-   | |_^
-   |
-note: the following variants exist on `TooManyVariants`
-  --> $DIR/repr-transparent.rs:59:5
-   |
+LL | enum TooManyVariants {
+   | ^^^^^^^^^^^^^^^^^^^^ needs exactly one variant, but has 2
 LL |     Foo(String),
-   |     ^^^^^^^^^^^
+   |     -----------
 LL |     Bar,
-   |     ^^^
+   |     --- too many variants in `TooManyVariants`
 
 error[E0690]: transparent union needs exactly one non-zero-sized field, but has 0
   --> $DIR/repr-transparent.rs:64:1
    |
-LL | / union UnitUnion {
-LL | |     u: (),
-LL | | }
-   | |_^
+LL | union UnitUnion {
+   | ^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 0
 
 error[E0690]: transparent union needs exactly one non-zero-sized field, but has 2
   --> $DIR/repr-transparent.rs:69:1
    |
-LL | / union TooManyFields {
-LL | |     u: u32,
-LL | |     s: i32
-LL | | }
-   | |_^
-   |
-note: the following non-zero-sized fields exist on `TooManyFields`:
-  --> $DIR/repr-transparent.rs:70:5
-   |
+LL | union TooManyFields {
+   | ^^^^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 2
 LL |     u: u32,
-   |     ^^^^^^
+   |     ------ this field is non-zero-sized
 LL |     s: i32
-   |     ^^^^^^
+   |     ------ this field is non-zero-sized
 
 error: aborting due to 15 previous errors
 
diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py
index a777279bd16..9e7c18b7f56 100755
--- a/src/tools/publish_toolstate.py
+++ b/src/tools/publish_toolstate.py
@@ -64,6 +64,7 @@ def maybe_delink(message):
 
 def issue(
     tool,
+    status,
     maintainers,
     relevant_pr_number,
     relevant_pr_user,
@@ -72,12 +73,16 @@ def issue(
     # Open an issue about the toolstate failure.
     assignees = [x.strip() for x in maintainers.split('@') if x != '']
     assignees.append(relevant_pr_user)
+    if status == 'test-fail':
+        status_description = 'has failing tests'
+    else:
+        status_description = 'no longer builds'
     response = urllib2.urlopen(urllib2.Request(
         gh_url(),
         json.dumps({
             'body': maybe_delink(textwrap.dedent('''\
             Hello, this is your friendly neighborhood mergebot.
-            After merging PR {}, I observed that the tool {} no longer builds.
+            After merging PR {}, I observed that the tool {} {}.
             A follow-up PR to the repository {} is needed to fix the fallout.
 
             cc @{}, do you think you would have time to do the follow-up work?
@@ -85,7 +90,10 @@ def issue(
 
             cc @{}, the PR reviewer, and @rust-lang/compiler -- nominating for prioritization.
 
-            ''').format(relevant_pr_number, tool, REPOS.get(tool), relevant_pr_user, pr_reviewer)),
+            ''').format(
+                relevant_pr_number, tool, status_description,
+                REPOS.get(tool), relevant_pr_user, pr_reviewer
+            )),
             'title': '`{}` no longer builds after {}'.format(tool, relevant_pr_number),
             'assignees': assignees,
             'labels': ['T-compiler', 'I-nominated'],
@@ -127,7 +135,7 @@ def update_latest(
         for status in latest:
             tool = status['tool']
             changed = False
-            build_failed = False
+            create_issue = False
 
             for os, s in current_status.items():
                 old = status[os]
@@ -145,14 +153,15 @@ def update_latest(
                         .format(tool, os, old, new)
                     message += '{} (cc {}, @rust-lang/infra).\n' \
                         .format(title, MAINTAINERS.get(tool))
-                    # only create issues for build failures. Other failures can be spurious
-                    if new == 'build-fail':
-                        build_failed = True
+                    # Most tools only create issues for build failures.
+                    # Other failures can be spurious.
+                    if new == 'build-fail' or (tool == 'miri' and new == 'test-fail'):
+                        create_issue = True
 
-            if build_failed:
+            if create_issue:
                 try:
                     issue(
-                        tool, MAINTAINERS.get(tool, ''),
+                        tool, new, MAINTAINERS.get(tool, ''),
                         relevant_pr_number, relevant_pr_user, pr_reviewer,
                     )
                 except IOError as e: