about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-05-02 02:01:31 +0000
committerbors <bors@rust-lang.org>2019-05-02 02:01:31 +0000
commit767f59462663fbc55a69d39fc5e1f7f83b6fb37d (patch)
tree895cfb402b31011b55559d0acf4cdc5d34326eec
parentea68bee369c9ebc0de35abcd39211fa0d4f9c84f (diff)
parent4ff12347d994d5c85cab250cedf223d9d0db8973 (diff)
downloadrust-767f59462663fbc55a69d39fc5e1f7f83b6fb37d.tar.gz
rust-767f59462663fbc55a69d39fc5e1f7f83b6fb37d.zip
Auto merge of #60460 - Centril:rollup-gz5bc8i, r=Centril
Rollup of 7 pull requests

Successful merges:

 - #59634 (Added an explanation for the E0704 error.)
 - #60348 (move some functions from parser.rs to diagostics.rs)
 - #60385 (Emit metadata files earlier)
 - #60428 (Refactor `eval_body_using_ecx` so that it doesn't need to query for MIR)
 - #60437 (Ensure that drop order of `async fn` matches `fn` and that users cannot refer to generated arguments.)
 - #60439 (doc: Warn about possible zombie apocalypse)
 - #60452 (Remove Context and ContextKind)

Failed merges:

r? @ghost
-rw-r--r--Cargo.lock2
-rw-r--r--src/librustc/hir/lowering.rs39
-rw-r--r--src/librustc/hir/map/def_collector.rs13
-rw-r--r--src/librustc/lint/context.rs15
-rw-r--r--src/librustc_codegen_llvm/base.rs40
-rw-r--r--src/librustc_codegen_llvm/lib.rs14
-rw-r--r--src/librustc_codegen_ssa/back/link.rs124
-rw-r--r--src/librustc_codegen_ssa/base.rs48
-rw-r--r--src/librustc_codegen_ssa/traits/backend.rs7
-rw-r--r--src/librustc_codegen_utils/codegen_backend.rs4
-rw-r--r--src/librustc_interface/Cargo.toml2
-rw-r--r--src/librustc_interface/passes.rs77
-rw-r--r--src/librustc_mir/borrow_check/error_reporting.rs76
-rw-r--r--src/librustc_mir/borrow_check/mod.rs203
-rw-r--r--src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs18
-rw-r--r--src/librustc_mir/borrow_check/nll/invalidation.rs82
-rw-r--r--src/librustc_mir/borrow_check/path_utils.rs3
-rw-r--r--src/librustc_mir/const_eval.rs41
-rw-r--r--src/librustc_mir/transform/const_prop.rs3
-rw-r--r--src/librustc_resolve/lib.rs38
-rw-r--r--src/libstd/process.rs12
-rw-r--r--src/libsyntax/ast.rs12
-rw-r--r--src/libsyntax/error_codes.rs30
-rw-r--r--src/libsyntax/ext/placeholders.rs5
-rw-r--r--src/libsyntax/mut_visit.rs14
-rw-r--r--src/libsyntax/parse/diagnostics.rs226
-rw-r--r--src/libsyntax/parse/mod.rs1
-rw-r--r--src/libsyntax/parse/parser.rs230
-rw-r--r--src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs4
-rw-r--r--src/test/run-pass/issue-54716.rs184
-rw-r--r--src/test/ui/async-await/auxiliary/arc_wake.rs64
-rw-r--r--src/test/ui/async-await/drop-order-for-async-fn-parameters.rs263
-rw-r--r--src/test/ui/async-await/drop-order-locals-are-hidden.rs11
-rw-r--r--src/test/ui/async-await/drop-order-locals-are-hidden.stderr15
-rw-r--r--src/test/ui/pub/pub-restricted.stderr1
35 files changed, 1132 insertions, 789 deletions
diff --git a/Cargo.lock b/Cargo.lock
index f6713496f5b..fd6a7a5604e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2802,6 +2802,7 @@ dependencies = [
  "rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc_allocator 0.0.0",
  "rustc_borrowck 0.0.0",
+ "rustc_codegen_ssa 0.0.0",
  "rustc_codegen_utils 0.0.0",
  "rustc_data_structures 0.0.0",
  "rustc_errors 0.0.0",
@@ -2821,6 +2822,7 @@ dependencies = [
  "syntax 0.0.0",
  "syntax_ext 0.0.0",
  "syntax_pos 0.0.0",
+ "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index f4209a39c83..6d57882976e 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -2996,8 +2996,33 @@ impl<'a> LoweringContext<'a> {
             if let IsAsync::Async { closure_id, ref arguments, .. } = asyncness {
                 let mut body = body.clone();
 
+                // Async function arguments are lowered into the closure body so that they are
+                // captured and so that the drop order matches the equivalent non-async functions.
+                //
+                //     async fn foo(<pattern>: <ty>, <pattern>: <ty>, <pattern>: <ty>) {
+                //       async move {
+                //       }
+                //     }
+                //
+                //     // ...becomes...
+                //     fn foo(__arg0: <ty>, __arg1: <ty>, __arg2: <ty>) {
+                //       async move {
+                //         let __arg2 = __arg2;
+                //         let <pattern> = __arg2;
+                //         let __arg1 = __arg1;
+                //         let <pattern> = __arg1;
+                //         let __arg0 = __arg0;
+                //         let <pattern> = __arg0;
+                //       }
+                //     }
+                //
+                // If `<pattern>` is a simple ident, then it is lowered to a single
+                // `let <pattern> = <pattern>;` statement as an optimization.
                 for a in arguments.iter().rev() {
-                    body.stmts.insert(0, a.stmt.clone());
+                    if let Some(pat_stmt) = a.pat_stmt.clone() {
+                        body.stmts.insert(0, pat_stmt);
+                    }
+                    body.stmts.insert(0, a.move_stmt.clone());
                 }
 
                 let async_expr = this.make_async_expr(
@@ -3093,7 +3118,11 @@ impl<'a> LoweringContext<'a> {
                         let mut decl = decl.clone();
                         // Replace the arguments of this async function with the generated
                         // arguments that will be moved into the closure.
-                        decl.inputs = arguments.clone().drain(..).map(|a| a.arg).collect();
+                        for (i, a) in arguments.clone().drain(..).enumerate() {
+                            if let Some(arg) = a.arg {
+                                decl.inputs[i] = arg;
+                            }
+                        }
                         lower_fn(&decl)
                     } else {
                         lower_fn(decl)
@@ -3590,7 +3619,11 @@ impl<'a> LoweringContext<'a> {
                     let mut sig = sig.clone();
                     // Replace the arguments of this async function with the generated
                     // arguments that will be moved into the closure.
-                    sig.decl.inputs = arguments.clone().drain(..).map(|a| a.arg).collect();
+                    for (i, a) in arguments.clone().drain(..).enumerate() {
+                        if let Some(arg) = a.arg {
+                            sig.decl.inputs[i] = arg;
+                        }
+                    }
                     lower_method(&sig)
                 } else {
                     lower_method(sig)
diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index 0fa97385322..78de8539859 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -94,7 +94,9 @@ impl<'a> DefCollector<'a> {
             // Walk the generated arguments for the `async fn`.
             for a in arguments {
                 use visit::Visitor;
-                this.visit_ty(&a.arg.ty);
+                if let Some(arg) = &a.arg {
+                    this.visit_ty(&arg.ty);
+                }
             }
 
             // We do not invoke `walk_fn_decl` as this will walk the arguments that are being
@@ -105,10 +107,13 @@ impl<'a> DefCollector<'a> {
                 *closure_id, DefPathData::ClosureExpr, REGULAR_SPACE, span,
             );
             this.with_parent(closure_def, |this| {
+                use visit::Visitor;
+                // Walk each of the generated statements before the regular block body.
                 for a in arguments {
-                    use visit::Visitor;
-                    // Walk each of the generated statements before the regular block body.
-                    this.visit_stmt(&a.stmt);
+                    this.visit_stmt(&a.move_stmt);
+                    if let Some(pat_stmt) = &a.pat_stmt {
+                        this.visit_stmt(&pat_stmt);
+                    }
                 }
 
                 visit::walk_block(this, &body);
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index f5cb4cfa29f..8d5c1798e0f 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -1334,14 +1334,19 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
         if let ast::IsAsync::Async { ref arguments, .. } = header.asyncness.node {
             for a in arguments {
                 // Visit the argument..
-                self.visit_pat(&a.arg.pat);
-                if let ast::ArgSource::AsyncFn(pat) = &a.arg.source {
-                    self.visit_pat(pat);
+                if let Some(arg) = &a.arg {
+                    self.visit_pat(&arg.pat);
+                    if let ast::ArgSource::AsyncFn(pat) = &arg.source {
+                        self.visit_pat(pat);
+                    }
+                    self.visit_ty(&arg.ty);
                 }
-                self.visit_ty(&a.arg.ty);
 
                 // ..and the statement.
-                self.visit_stmt(&a.stmt);
+                self.visit_stmt(&a.move_stmt);
+                if let Some(pat_stmt) = &a.pat_stmt {
+                    self.visit_stmt(&pat_stmt);
+                }
             }
         }
     }
diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs
index 7ea5e912309..9077e89a402 100644
--- a/src/librustc_codegen_llvm/base.rs
+++ b/src/librustc_codegen_llvm/base.rs
@@ -28,7 +28,7 @@ use rustc::mir::mono::{Linkage, Visibility, Stats};
 use rustc::middle::cstore::{EncodedMetadata};
 use rustc::ty::TyCtxt;
 use rustc::middle::exported_symbols;
-use rustc::session::config::{self, DebugInfo};
+use rustc::session::config::DebugInfo;
 use rustc_codegen_ssa::mono_item::MonoItemExt;
 use rustc_data_structures::small_c_str::SmallCStr;
 
@@ -42,47 +42,16 @@ use rustc::hir::CodegenFnAttrs;
 
 use crate::value::Value;
 
-
-pub fn write_metadata<'a, 'gcx>(
+pub fn write_compressed_metadata<'a, 'gcx>(
     tcx: TyCtxt<'a, 'gcx, 'gcx>,
+    metadata: &EncodedMetadata,
     llvm_module: &mut ModuleLlvm
-) -> EncodedMetadata {
+) {
     use std::io::Write;
     use flate2::Compression;
     use flate2::write::DeflateEncoder;
 
     let (metadata_llcx, metadata_llmod) = (&*llvm_module.llcx, llvm_module.llmod());
-
-    #[derive(PartialEq, Eq, PartialOrd, Ord)]
-    enum MetadataKind {
-        None,
-        Uncompressed,
-        Compressed
-    }
-
-    let kind = tcx.sess.crate_types.borrow().iter().map(|ty| {
-        match *ty {
-            config::CrateType::Executable |
-            config::CrateType::Staticlib |
-            config::CrateType::Cdylib => MetadataKind::None,
-
-            config::CrateType::Rlib => MetadataKind::Uncompressed,
-
-            config::CrateType::Dylib |
-            config::CrateType::ProcMacro => MetadataKind::Compressed,
-        }
-    }).max().unwrap_or(MetadataKind::None);
-
-    if kind == MetadataKind::None {
-        return EncodedMetadata::new();
-    }
-
-    let metadata = tcx.encode_metadata();
-    if kind == MetadataKind::Uncompressed {
-        return metadata;
-    }
-
-    assert!(kind == MetadataKind::Compressed);
     let mut compressed = tcx.metadata_encoding_version();
     DeflateEncoder::new(&mut compressed, Compression::fast())
         .write_all(&metadata.raw_data).unwrap();
@@ -107,7 +76,6 @@ pub fn write_metadata<'a, 'gcx>(
         let directive = CString::new(directive).unwrap();
         llvm::LLVMSetModuleInlineAsm(metadata_llmod, directive.as_ptr())
     }
-    return metadata;
 }
 
 pub struct ValueIter<'ll> {
diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs
index 08424e7c322..09b284052b3 100644
--- a/src/librustc_codegen_llvm/lib.rs
+++ b/src/librustc_codegen_llvm/lib.rs
@@ -110,12 +110,13 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
         ModuleLlvm::new_metadata(tcx, mod_name)
     }
 
-    fn write_metadata<'b, 'gcx>(
+    fn write_compressed_metadata<'b, 'gcx>(
         &self,
         tcx: TyCtxt<'b, 'gcx, 'gcx>,
-        metadata: &mut ModuleLlvm
-    ) -> EncodedMetadata {
-        base::write_metadata(tcx, metadata)
+        metadata: &EncodedMetadata,
+        llvm_module: &mut ModuleLlvm
+    ) {
+        base::write_compressed_metadata(tcx, metadata, llvm_module)
     }
     fn codegen_allocator<'b, 'gcx>(
         &self,
@@ -289,9 +290,12 @@ impl CodegenBackend for LlvmCodegenBackend {
     fn codegen_crate<'b, 'tcx>(
         &self,
         tcx: TyCtxt<'b, 'tcx, 'tcx>,
+        metadata: EncodedMetadata,
+        need_metadata_module: bool,
         rx: mpsc::Receiver<Box<dyn Any + Send>>
     ) -> Box<dyn Any> {
-        box rustc_codegen_ssa::base::codegen_crate(LlvmCodegenBackend(()), tcx, rx)
+        box rustc_codegen_ssa::base::codegen_crate(
+            LlvmCodegenBackend(()), tcx, metadata, need_metadata_module, rx)
     }
 
     fn join_codegen_and_link(
diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs
index 4cae20b698a..f25891d77ce 100644
--- a/src/librustc_codegen_ssa/back/link.rs
+++ b/src/librustc_codegen_ssa/back/link.rs
@@ -7,7 +7,7 @@ use rustc::session::config::{
 };
 use rustc::session::search_paths::PathKind;
 use rustc::middle::dependency_format::Linkage;
-use rustc::middle::cstore::{LibSource, NativeLibrary, NativeLibraryKind};
+use rustc::middle::cstore::{EncodedMetadata, LibSource, NativeLibrary, NativeLibraryKind};
 use rustc::util::common::{time, time_ext};
 use rustc::hir::def_id::CrateNum;
 use rustc_data_structures::fx::FxHashSet;
@@ -50,9 +50,9 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
                                               outputs: &OutputFilenames,
                                               crate_name: &str,
                                               target_cpu: &str) {
+    let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata);
     for &crate_type in sess.crate_types.borrow().iter() {
         // Ignore executable crates if we have -Z no-codegen, as they will error.
-        let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata);
         if (sess.opts.debugging_opts.no_codegen || !sess.opts.output_types.should_codegen()) &&
            !output_metadata &&
            crate_type == config::CrateType::Executable {
@@ -63,12 +63,43 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
            bug!("invalid output type `{:?}` for target os `{}`",
                 crate_type, sess.opts.target_triple);
         }
-        link_binary_output::<B>(sess,
-                                codegen_results,
-                                crate_type,
-                                outputs,
-                                crate_name,
-                                target_cpu);
+
+        for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) {
+            check_file_is_writeable(obj, sess);
+        }
+
+        let tmpdir = TempFileBuilder::new().prefix("rustc").tempdir().unwrap_or_else(|err|
+            sess.fatal(&format!("couldn't create a temp dir: {}", err)));
+
+        if outputs.outputs.should_codegen() {
+            let out_filename = out_filename(sess, crate_type, outputs, crate_name);
+            match crate_type {
+                config::CrateType::Rlib => {
+                    link_rlib::<B>(sess,
+                              codegen_results,
+                              RlibFlavor::Normal,
+                              &out_filename,
+                              &tmpdir).build();
+                }
+                config::CrateType::Staticlib => {
+                    link_staticlib::<B>(sess, codegen_results, &out_filename, &tmpdir);
+                }
+                _ => {
+                    link_natively::<B>(
+                        sess,
+                        crate_type,
+                        &out_filename,
+                        codegen_results,
+                        tmpdir.path(),
+                        target_cpu,
+                    );
+                }
+            }
+        }
+
+        if sess.opts.cg.save_temps {
+            let _ = tmpdir.into_path();
+        }
     }
 
     // Remove the temporary object file and metadata if we aren't saving temps
@@ -85,7 +116,7 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
             if let Some(ref obj) = metadata_module.object {
                 remove(sess, obj);
             }
-         }
+        }
         if let Some(ref allocator_module) = codegen_results.allocator_module {
             if let Some(ref obj) = allocator_module.object {
                 remove(sess, obj);
@@ -97,73 +128,6 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
     }
 }
 
-fn link_binary_output<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
-                                                 codegen_results: &CodegenResults,
-                                                 crate_type: config::CrateType,
-                                                 outputs: &OutputFilenames,
-                                                 crate_name: &str,
-                                                 target_cpu: &str) {
-    for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) {
-        check_file_is_writeable(obj, sess);
-    }
-
-    if outputs.outputs.contains_key(&OutputType::Metadata) {
-        let out_filename = filename_for_metadata(sess, crate_name, outputs);
-        // To avoid races with another rustc process scanning the output directory,
-        // we need to write the file somewhere else and atomically move it to its
-        // final destination, with a `fs::rename` call. In order for the rename to
-        // always succeed, the temporary file needs to be on the same filesystem,
-        // which is why we create it inside the output directory specifically.
-        let metadata_tmpdir = TempFileBuilder::new()
-            .prefix("rmeta")
-            .tempdir_in(out_filename.parent().unwrap())
-            .unwrap_or_else(|err| sess.fatal(&format!("couldn't create a temp dir: {}", err)));
-        let metadata = emit_metadata(sess, codegen_results, &metadata_tmpdir);
-        match fs::rename(&metadata, &out_filename) {
-            Ok(_) => {
-                if sess.opts.debugging_opts.emit_directives {
-                    sess.parse_sess.span_diagnostic.maybe_emit_json_directive(
-                        format!("metadata file written: {}", out_filename.display()));
-                }
-            }
-            Err(e) => sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)),
-        }
-    }
-
-    let tmpdir = TempFileBuilder::new().prefix("rustc").tempdir().unwrap_or_else(|err|
-        sess.fatal(&format!("couldn't create a temp dir: {}", err)));
-
-    if outputs.outputs.should_codegen() {
-        let out_filename = out_filename(sess, crate_type, outputs, crate_name);
-        match crate_type {
-            config::CrateType::Rlib => {
-                link_rlib::<B>(sess,
-                          codegen_results,
-                          RlibFlavor::Normal,
-                          &out_filename,
-                          &tmpdir).build();
-            }
-            config::CrateType::Staticlib => {
-                link_staticlib::<B>(sess, codegen_results, &out_filename, &tmpdir);
-            }
-            _ => {
-                link_natively::<B>(
-                    sess,
-                    crate_type,
-                    &out_filename,
-                    codegen_results,
-                    tmpdir.path(),
-                    target_cpu,
-                );
-            }
-        }
-    }
-
-    if sess.opts.cg.save_temps {
-        let _ = tmpdir.into_path();
-    }
-}
-
 // The third parameter is for env vars, used on windows to set up the
 // path for MSVC to find its DLLs, and gcc to find its bundled
 // toolchain
@@ -261,13 +225,13 @@ pub fn each_linked_rlib(sess: &Session,
 /// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a
 /// directory being searched for `extern crate` (observing an incomplete file).
 /// The returned path is the temporary file containing the complete metadata.
-fn emit_metadata<'a>(
+pub fn emit_metadata<'a>(
     sess: &'a Session,
-    codegen_results: &CodegenResults,
+    metadata: &EncodedMetadata,
     tmpdir: &TempDir
 ) -> PathBuf {
     let out_filename = tmpdir.path().join(METADATA_FILENAME);
-    let result = fs::write(&out_filename, &codegen_results.metadata.raw_data);
+    let result = fs::write(&out_filename, &metadata.raw_data);
 
     if let Err(e) = result {
         sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
@@ -351,7 +315,7 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
         RlibFlavor::Normal => {
             // Instead of putting the metadata in an object file section, rlibs
             // contain the metadata in a separate file.
-            ab.add_file(&emit_metadata(sess, codegen_results, tmpdir));
+            ab.add_file(&emit_metadata(sess, &codegen_results.metadata, tmpdir));
 
             // For LTO purposes, the bytecode of this library is also inserted
             // into the archive.
diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs
index 3046c069981..3cd47dfbb29 100644
--- a/src/librustc_codegen_ssa/base.rs
+++ b/src/librustc_codegen_ssa/base.rs
@@ -17,6 +17,7 @@ use crate::{ModuleCodegen, ModuleKind, CachedModuleCodegen};
 
 use rustc::dep_graph::cgu_reuse_tracker::CguReuse;
 use rustc::hir::def_id::{DefId, LOCAL_CRATE};
+use rustc::middle::cstore::EncodedMetadata;
 use rustc::middle::lang_items::StartFnLangItem;
 use rustc::middle::weak_lang_items;
 use rustc::mir::mono::{Stats, CodegenUnitNameBuilder};
@@ -25,7 +26,7 @@ use rustc::ty::layout::{self, Align, TyLayout, LayoutOf, VariantIdx, HasTyCtxt};
 use rustc::ty::query::Providers;
 use rustc::middle::cstore::{self, LinkagePreference};
 use rustc::util::common::{time, print_time_passes_entry};
-use rustc::session::config::{self, CrateType, EntryFnType, Lto};
+use rustc::session::config::{self, EntryFnType, Lto};
 use rustc::session::Session;
 use rustc_mir::monomorphize::item::DefPathBasedNames;
 use rustc_mir::monomorphize::Instance;
@@ -530,26 +531,13 @@ pub const CODEGEN_WORKER_ID: usize = ::std::usize::MAX;
 pub fn codegen_crate<B: ExtraBackendMethods>(
     backend: B,
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    metadata: EncodedMetadata,
+    need_metadata_module: bool,
     rx: mpsc::Receiver<Box<dyn Any + Send>>
 ) -> OngoingCodegen<B> {
 
     check_for_rustc_errors_attr(tcx);
 
-    let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
-
-    // Codegen the metadata.
-    tcx.sess.profiler(|p| p.start_activity("codegen crate metadata"));
-
-    let metadata_cgu_name = cgu_name_builder.build_cgu_name(LOCAL_CRATE,
-                                                            &["crate"],
-                                                            Some("metadata")).as_str()
-                                                                             .to_string();
-    let mut metadata_llvm_module = backend.new_metadata(tcx, &metadata_cgu_name);
-    let metadata = time(tcx.sess, "write metadata", || {
-        backend.write_metadata(tcx, &mut metadata_llvm_module)
-    });
-    tcx.sess.profiler(|p| p.end_activity("codegen crate metadata"));
-
     // Skip crate items and just output metadata in -Z no-codegen mode.
     if tcx.sess.opts.debugging_opts.no_codegen ||
        !tcx.sess.opts.output_types.should_codegen() {
@@ -569,6 +557,8 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
         return ongoing_codegen;
     }
 
+    let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
+
     // Run the monomorphization collector and partition the collected items into
     // codegen units.
     let codegen_units = tcx.collect_and_partition_mono_items(LOCAL_CRATE).1;
@@ -632,17 +622,21 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
         ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, allocator_module);
     }
 
-    let needs_metadata_module = tcx.sess.crate_types.borrow().iter().any(|ct| {
-        match *ct {
-            CrateType::Dylib |
-            CrateType::ProcMacro => true,
-            CrateType::Executable |
-            CrateType::Rlib |
-            CrateType::Staticlib |
-            CrateType::Cdylib => false,
-        }
-    });
-    if needs_metadata_module {
+    if need_metadata_module {
+        // Codegen the encoded metadata.
+        tcx.sess.profiler(|p| p.start_activity("codegen crate metadata"));
+
+        let metadata_cgu_name = cgu_name_builder.build_cgu_name(LOCAL_CRATE,
+                                                                &["crate"],
+                                                                Some("metadata")).as_str()
+                                                                                 .to_string();
+        let mut metadata_llvm_module = backend.new_metadata(tcx, &metadata_cgu_name);
+        time(tcx.sess, "write compressed metadata", || {
+            backend.write_compressed_metadata(tcx, &ongoing_codegen.metadata,
+                                              &mut metadata_llvm_module);
+        });
+        tcx.sess.profiler(|p| p.end_activity("codegen crate metadata"));
+
         let metadata_module = ModuleCodegen {
             name: metadata_cgu_name,
             module_llvm: metadata_llvm_module,
diff --git a/src/librustc_codegen_ssa/traits/backend.rs b/src/librustc_codegen_ssa/traits/backend.rs
index a9e0eadb198..530eba516a6 100644
--- a/src/librustc_codegen_ssa/traits/backend.rs
+++ b/src/librustc_codegen_ssa/traits/backend.rs
@@ -33,11 +33,12 @@ impl<'tcx, T> Backend<'tcx> for T where
 
 pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Send {
     fn new_metadata(&self, sess: TyCtxt<'_, '_, '_>, mod_name: &str) -> Self::Module;
-    fn write_metadata<'b, 'gcx>(
+    fn write_compressed_metadata<'b, 'gcx>(
         &self,
         tcx: TyCtxt<'b, 'gcx, 'gcx>,
-        metadata: &mut Self::Module,
-    ) -> EncodedMetadata;
+        metadata: &EncodedMetadata,
+        llvm_module: &mut Self::Module,
+    );
     fn codegen_allocator<'b, 'gcx>(
         &self,
         tcx: TyCtxt<'b, 'gcx, 'gcx>,
diff --git a/src/librustc_codegen_utils/codegen_backend.rs b/src/librustc_codegen_utils/codegen_backend.rs
index 56eaffb1ca3..191c6605b43 100644
--- a/src/librustc_codegen_utils/codegen_backend.rs
+++ b/src/librustc_codegen_utils/codegen_backend.rs
@@ -18,7 +18,7 @@ use rustc::util::common::ErrorReported;
 use rustc::session::config::{OutputFilenames, PrintRequest};
 use rustc::ty::TyCtxt;
 use rustc::ty::query::Providers;
-use rustc::middle::cstore::MetadataLoader;
+use rustc::middle::cstore::{EncodedMetadata, MetadataLoader};
 use rustc::dep_graph::DepGraph;
 
 pub use rustc_data_structures::sync::MetadataRef;
@@ -37,6 +37,8 @@ pub trait CodegenBackend {
     fn codegen_crate<'a, 'tcx>(
         &self,
         tcx: TyCtxt<'a, 'tcx, 'tcx>,
+        metadata: EncodedMetadata,
+        need_metadata_module: bool,
         rx: mpsc::Receiver<Box<dyn Any + Send>>
     ) -> Box<dyn Any>;
 
diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml
index fa2a5d2fc89..bcaa4216109 100644
--- a/src/librustc_interface/Cargo.toml
+++ b/src/librustc_interface/Cargo.toml
@@ -24,6 +24,7 @@ rustc_borrowck = { path = "../librustc_borrowck" }
 rustc_incremental = { path = "../librustc_incremental" }
 rustc_traits = { path = "../librustc_traits" }
 rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_codegen_ssa = { path = "../librustc_codegen_ssa" }
 rustc_codegen_utils = { path = "../librustc_codegen_utils" }
 rustc_metadata = { path = "../librustc_metadata" }
 rustc_mir = { path = "../librustc_mir" }
@@ -34,3 +35,4 @@ rustc_errors = { path = "../librustc_errors" }
 rustc_plugin = { path = "../librustc_plugin" }
 rustc_privacy = { path = "../librustc_privacy" }
 rustc_resolve = { path = "../librustc_resolve" }
+tempfile = "3.0.5"
diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs
index f8b1271b8b5..6d3115c6213 100644
--- a/src/librustc_interface/passes.rs
+++ b/src/librustc_interface/passes.rs
@@ -16,11 +16,13 @@ use rustc::traits;
 use rustc::util::common::{time, ErrorReported};
 use rustc::util::profiling::ProfileCategory;
 use rustc::session::{CompileResult, CrateDisambiguator, Session};
-use rustc::session::config::{self, Input, OutputFilenames, OutputType};
+use rustc::session::config::{self, CrateType, Input, OutputFilenames, OutputType};
 use rustc::session::search_paths::PathKind;
 use rustc_allocator as allocator;
 use rustc_borrowck as borrowck;
+use rustc_codegen_ssa::back::link::emit_metadata;
 use rustc_codegen_utils::codegen_backend::CodegenBackend;
+use rustc_codegen_utils::link::filename_for_metadata;
 use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel};
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::stable_hasher::StableHasher;
@@ -50,6 +52,7 @@ use syntax_pos::{FileName, hygiene};
 use syntax_ext;
 
 use serialize::json;
+use tempfile::Builder as TempFileBuilder;
 
 use std::any::Any;
 use std::env;
@@ -999,6 +1002,68 @@ fn analysis<'tcx>(
     Ok(())
 }
 
+fn encode_and_write_metadata<'tcx>(
+    tcx: TyCtxt<'_, 'tcx, 'tcx>,
+    outputs: &OutputFilenames,
+) -> (middle::cstore::EncodedMetadata, bool) {
+    #[derive(PartialEq, Eq, PartialOrd, Ord)]
+    enum MetadataKind {
+        None,
+        Uncompressed,
+        Compressed
+    }
+
+    let metadata_kind = tcx.sess.crate_types.borrow().iter().map(|ty| {
+        match *ty {
+            CrateType::Executable |
+            CrateType::Staticlib |
+            CrateType::Cdylib => MetadataKind::None,
+
+            CrateType::Rlib => MetadataKind::Uncompressed,
+
+            CrateType::Dylib |
+            CrateType::ProcMacro => MetadataKind::Compressed,
+        }
+    }).max().unwrap_or(MetadataKind::None);
+
+    let metadata = match metadata_kind {
+        MetadataKind::None => middle::cstore::EncodedMetadata::new(),
+        MetadataKind::Uncompressed |
+        MetadataKind::Compressed => tcx.encode_metadata(),
+    };
+
+    let need_metadata_file = tcx.sess.opts.output_types.contains_key(&OutputType::Metadata);
+    if need_metadata_file {
+        let crate_name = &tcx.crate_name(LOCAL_CRATE).as_str();
+        let out_filename = filename_for_metadata(tcx.sess, crate_name, outputs);
+        // To avoid races with another rustc process scanning the output directory,
+        // we need to write the file somewhere else and atomically move it to its
+        // final destination, with an `fs::rename` call. In order for the rename to
+        // always succeed, the temporary file needs to be on the same filesystem,
+        // which is why we create it inside the output directory specifically.
+        let metadata_tmpdir = TempFileBuilder::new()
+            .prefix("rmeta")
+            .tempdir_in(out_filename.parent().unwrap())
+            .unwrap_or_else(|err| {
+                tcx.sess.fatal(&format!("couldn't create a temp dir: {}", err))
+            });
+        let metadata_filename = emit_metadata(tcx.sess, &metadata, &metadata_tmpdir);
+        match std::fs::rename(&metadata_filename, &out_filename) {
+            Ok(_) => {
+                if tcx.sess.opts.debugging_opts.emit_directives {
+                    tcx.sess.parse_sess.span_diagnostic.maybe_emit_json_directive(
+                        format!("metadata file written: {}", out_filename.display()));
+                }
+            }
+            Err(e) => tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)),
+        }
+    }
+
+    let need_metadata_module = metadata_kind == MetadataKind::Compressed;
+
+    (metadata, need_metadata_module)
+}
+
 /// Runs the codegen backend, after which the AST and analysis can
 /// be discarded.
 pub fn start_codegen<'tcx>(
@@ -1013,11 +1078,17 @@ pub fn start_codegen<'tcx>(
     }
 
     time(tcx.sess, "resolving dependency formats", || {
-        ::rustc::middle::dependency_format::calculate(tcx)
+        middle::dependency_format::calculate(tcx)
+    });
+
+    let (metadata, need_metadata_module) = time(tcx.sess, "metadata encoding and writing", || {
+        encode_and_write_metadata(tcx, outputs)
     });
 
     tcx.sess.profiler(|p| p.start_activity("codegen crate"));
-    let codegen = time(tcx.sess, "codegen", move || codegen_backend.codegen_crate(tcx, rx));
+    let codegen = time(tcx.sess, "codegen", move || {
+        codegen_backend.codegen_crate(tcx, metadata, need_metadata_module, rx)
+    });
     tcx.sess.profiler(|p| p.end_activity("codegen crate"));
 
     if log_enabled!(::log::Level::Info) {
diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs
index a8ebe85e251..ed42326d7d5 100644
--- a/src/librustc_mir/borrow_check/error_reporting.rs
+++ b/src/librustc_mir/borrow_check/error_reporting.rs
@@ -22,7 +22,7 @@ use syntax_pos::Span;
 use syntax::source_map::CompilerDesugaringKind;
 
 use super::borrow_set::BorrowData;
-use super::{Context, MirBorrowckCtxt};
+use super::{MirBorrowckCtxt};
 use super::{InitializationRequiringAction, PrefixSet};
 use crate::dataflow::drop_flag_effects;
 use crate::dataflow::indexes::{MovePathIndex, MoveOutIndex};
@@ -42,22 +42,22 @@ struct MoveSite {
 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
     pub(super) fn report_use_of_moved_or_uninitialized(
         &mut self,
-        context: Context,
+        location: Location,
         desired_action: InitializationRequiringAction,
         (moved_place, used_place, span): (&Place<'tcx>, &Place<'tcx>, Span),
         mpi: MovePathIndex,
     ) {
         debug!(
-            "report_use_of_moved_or_uninitialized: context={:?} desired_action={:?} \
+            "report_use_of_moved_or_uninitialized: location={:?} desired_action={:?} \
              moved_place={:?} used_place={:?} span={:?} mpi={:?}",
-            context, desired_action, moved_place, used_place, span, mpi
+            location, desired_action, moved_place, used_place, span, mpi
         );
 
-        let use_spans = self.move_spans(moved_place, context.loc)
-            .or_else(|| self.borrow_spans(span, context.loc));
+        let use_spans = self.move_spans(moved_place, location)
+            .or_else(|| self.borrow_spans(span, location));
         let span = use_spans.args_or_use();
 
-        let move_site_vec = self.get_moved_indexes(context, mpi);
+        let move_site_vec = self.get_moved_indexes(location, mpi);
         debug!(
             "report_use_of_moved_or_uninitialized: move_site_vec={:?}",
             move_site_vec
@@ -125,7 +125,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             );
 
             self.add_moved_or_invoked_closure_note(
-                context.loc,
+                location,
                 used_place,
                 &mut err,
             );
@@ -261,13 +261,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
 
     pub(super) fn report_move_out_while_borrowed(
         &mut self,
-        context: Context,
+        location: Location,
         (place, span): (&Place<'tcx>, Span),
         borrow: &BorrowData<'tcx>,
     ) {
         debug!(
-            "report_move_out_while_borrowed: context={:?} place={:?} span={:?} borrow={:?}",
-            context, place, span, borrow
+            "report_move_out_while_borrowed: location={:?} place={:?} span={:?} borrow={:?}",
+            location, place, span, borrow
         );
         let tcx = self.infcx.tcx;
         let value_msg = match self.describe_place(place) {
@@ -282,7 +282,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         let borrow_spans = self.retrieve_borrow_spans(borrow);
         let borrow_span = borrow_spans.args_or_use();
 
-        let move_spans = self.move_spans(place, context.loc);
+        let move_spans = self.move_spans(place, location);
         let span = move_spans.args_or_use();
 
         let mut err = tcx.cannot_move_when_borrowed(
@@ -304,7 +304,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         );
 
         self.explain_why_borrow_contains_point(
-            context,
+            location,
             borrow,
             None,
         ).add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", Some(borrow_span));
@@ -313,7 +313,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
 
     pub(super) fn report_use_while_mutably_borrowed(
         &mut self,
-        context: Context,
+        location: Location,
         (place, _span): (&Place<'tcx>, Span),
         borrow: &BorrowData<'tcx>,
     ) -> DiagnosticBuilder<'cx> {
@@ -324,7 +324,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
 
         // Conflicting borrows are reported separately, so only check for move
         // captures.
-        let use_spans = self.move_spans(place, context.loc);
+        let use_spans = self.move_spans(place, location);
         let span = use_spans.var_or_use();
 
         let mut err = tcx.cannot_use_when_mutably_borrowed(
@@ -343,14 +343,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             format!("borrow occurs due to use of `{}`{}", desc_place, borrow_spans.describe())
         });
 
-        self.explain_why_borrow_contains_point(context, borrow, None)
+        self.explain_why_borrow_contains_point(location, borrow, None)
             .add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", None);
         err
     }
 
     pub(super) fn report_conflicting_borrow(
         &mut self,
-        context: Context,
+        location: Location,
         (place, span): (&Place<'tcx>, Span),
         gen_borrow_kind: BorrowKind,
         issued_borrow: &BorrowData<'tcx>,
@@ -358,7 +358,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         let issued_spans = self.retrieve_borrow_spans(issued_borrow);
         let issued_span = issued_spans.args_or_use();
 
-        let borrow_spans = self.borrow_spans(span, context.loc);
+        let borrow_spans = self.borrow_spans(span, location);
         let span = borrow_spans.args_or_use();
 
         let container_name = if issued_spans.for_generator() || borrow_spans.for_generator() {
@@ -370,7 +370,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         let (desc_place, msg_place, msg_borrow, union_type_name) =
             self.describe_place_for_conflicting_borrow(place, &issued_borrow.borrowed_place);
 
-        let explanation = self.explain_why_borrow_contains_point(context, issued_borrow, None);
+        let explanation = self.explain_why_borrow_contains_point(location, issued_borrow, None);
         let second_borrow_desc = if explanation.is_explained() {
             "second "
         } else {
@@ -671,7 +671,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
     /// `Drop::drop` with an aliasing borrow.)
     pub(super) fn report_borrowed_value_does_not_live_long_enough(
         &mut self,
-        context: Context,
+        location: Location,
         borrow: &BorrowData<'tcx>,
         place_span: (&Place<'tcx>, Span),
         kind: Option<WriteKind>,
@@ -680,7 +680,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             "report_borrowed_value_does_not_live_long_enough(\
              {:?}, {:?}, {:?}, {:?}\
              )",
-            context, borrow, place_span, kind
+            location, borrow, place_span, kind
         );
 
         let drop_span = place_span.1;
@@ -719,7 +719,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             // destructor conflict.
             if !borrow.borrowed_place.is_prefix_of(place_span.0) {
                 self.report_borrow_conflicts_with_destructor(
-                    context, borrow, place_span, kind, dropped_ty,
+                    location, borrow, place_span, kind, dropped_ty,
                 );
                 return;
             }
@@ -728,7 +728,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         let place_desc = self.describe_place(&borrow.borrowed_place);
 
         let kind_place = kind.filter(|_| place_desc.is_some()).map(|k| (k, place_span.0));
-        let explanation = self.explain_why_borrow_contains_point(context, &borrow, kind_place);
+        let explanation = self.explain_why_borrow_contains_point(location, &borrow, kind_place);
 
         let err = match (place_desc, explanation) {
             (Some(_), _) if self.is_place_thread_local(root_place) => {
@@ -784,7 +784,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                 },
             ) => self.report_escaping_data(borrow_span, name, upvar_span, upvar_name, span),
             (Some(name), explanation) => self.report_local_value_does_not_live_long_enough(
-                context,
+                location,
                 &name,
                 &scope_tree,
                 &borrow,
@@ -793,7 +793,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                 explanation,
             ),
             (None, explanation) => self.report_temporary_value_does_not_live_long_enough(
-                context,
+                location,
                 &scope_tree,
                 &borrow,
                 drop_span,
@@ -808,7 +808,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
 
     fn report_local_value_does_not_live_long_enough(
         &mut self,
-        context: Context,
+        location: Location,
         name: &str,
         scope_tree: &'tcx ScopeTree,
         borrow: &BorrowData<'tcx>,
@@ -820,7 +820,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             "report_local_value_does_not_live_long_enough(\
              {:?}, {:?}, {:?}, {:?}, {:?}, {:?}\
              )",
-            context, name, scope_tree, borrow, drop_span, borrow_spans
+            location, name, scope_tree, borrow, drop_span, borrow_spans
         );
 
         let borrow_span = borrow_spans.var_or_use();
@@ -914,7 +914,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
 
     fn report_borrow_conflicts_with_destructor(
         &mut self,
-        context: Context,
+        location: Location,
         borrow: &BorrowData<'tcx>,
         (place, drop_span): (&Place<'tcx>, Span),
         kind: Option<WriteKind>,
@@ -924,7 +924,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             "report_borrow_conflicts_with_destructor(\
              {:?}, {:?}, ({:?}, {:?}), {:?}\
              )",
-            context, borrow, place, drop_span, kind,
+            location, borrow, place, drop_span, kind,
         );
 
         let borrow_spans = self.retrieve_borrow_spans(borrow);
@@ -957,7 +957,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
 
         // Only give this note and suggestion if they could be relevant.
         let explanation =
-            self.explain_why_borrow_contains_point(context, borrow, kind.map(|k| (k, place)));
+            self.explain_why_borrow_contains_point(location, borrow, kind.map(|k| (k, place)));
         match explanation {
             BorrowExplanation::UsedLater { .. }
             | BorrowExplanation::UsedLaterWhenDropped { .. } => {
@@ -998,7 +998,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
 
     fn report_temporary_value_does_not_live_long_enough(
         &mut self,
-        context: Context,
+        location: Location,
         scope_tree: &'tcx ScopeTree,
         borrow: &BorrowData<'tcx>,
         drop_span: Span,
@@ -1010,7 +1010,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             "report_temporary_value_does_not_live_long_enough(\
              {:?}, {:?}, {:?}, {:?}, {:?}\
              )",
-            context, scope_tree, borrow, drop_span, proper_span
+            location, scope_tree, borrow, drop_span, proper_span
         );
 
         if let BorrowExplanation::MustBeValidFor {
@@ -1246,12 +1246,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         err
     }
 
-    fn get_moved_indexes(&mut self, context: Context, mpi: MovePathIndex) -> Vec<MoveSite> {
+    fn get_moved_indexes(&mut self, location: Location, mpi: MovePathIndex) -> Vec<MoveSite> {
         let mir = self.mir;
 
         let mut stack = Vec::new();
-        stack.extend(mir.predecessor_locations(context.loc).map(|predecessor| {
-            let is_back_edge = context.loc.dominates(predecessor, &self.dominators);
+        stack.extend(mir.predecessor_locations(location).map(|predecessor| {
+            let is_back_edge = location.dominates(predecessor, &self.dominators);
             (predecessor, is_back_edge)
         }));
 
@@ -1348,7 +1348,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
 
     pub(super) fn report_illegal_mutation_of_borrowed(
         &mut self,
-        context: Context,
+        location: Location,
         (place, span): (&Place<'tcx>, Span),
         loan: &BorrowData<'tcx>,
     ) {
@@ -1386,7 +1386,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             format!("borrow occurs due to use{}", loan_spans.describe()),
         );
 
-        self.explain_why_borrow_contains_point(context, loan, None)
+        self.explain_why_borrow_contains_point(location, loan, None)
             .add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", None);
 
         err.buffer(&mut self.errors_buffer);
@@ -1400,7 +1400,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
     /// assignment to `x.f`).
     pub(super) fn report_illegal_reassignment(
         &mut self,
-        _context: Context,
+        _location: Location,
         (place, span): (&Place<'tcx>, Span),
         assigned_span: Span,
         err_place: &Place<'tcx>,
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 169d5652359..1d65a018dd6 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -302,11 +302,12 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
 
     // Convert any reservation warnings into lints.
     let reservation_warnings = mem::replace(&mut mbcx.reservation_warnings, Default::default());
-    for (_, (place, span, context, bk, borrow)) in reservation_warnings {
-        let mut initial_diag = mbcx.report_conflicting_borrow(context, (&place, span), bk, &borrow);
+    for (_, (place, span, location, bk, borrow)) in reservation_warnings {
+        let mut initial_diag =
+            mbcx.report_conflicting_borrow(location, (&place, span), bk, &borrow);
 
         let lint_root = if let ClearCrossCrate::Set(ref vsi) = mbcx.mir.source_scope_local_data {
-            let scope = mbcx.mir.source_info(context.loc).scope;
+            let scope = mbcx.mir.source_info(location).scope;
             vsi[scope].lint_root
         } else {
             id
@@ -483,7 +484,7 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
     /// for the activation of the borrow.
     reservation_warnings: FxHashMap<
         BorrowIndex,
-        (Place<'tcx>, Span, Context, BorrowKind, BorrowData<'tcx>)
+        (Place<'tcx>, Span, Location, BorrowKind, BorrowData<'tcx>)
     >,
     /// This field keeps track of move errors that are to be reported for given move indicies.
     ///
@@ -559,14 +560,13 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
         match stmt.kind {
             StatementKind::Assign(ref lhs, ref rhs) => {
                 self.consume_rvalue(
-                    ContextKind::AssignRhs.new(location),
-                    (rhs, span),
                     location,
+                    (rhs, span),
                     flow_state,
                 );
 
                 self.mutate_place(
-                    ContextKind::AssignLhs.new(location),
+                    location,
                     (lhs, span),
                     Shallow(None),
                     JustWrite,
@@ -585,7 +585,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
                 //      match x {};
                 // from compiling.
                 self.check_if_path_or_subpath_is_moved(
-                    ContextKind::FakeRead.new(location),
+                    location,
                     InitializationRequiringAction::Use,
                     (place, span),
                     flow_state,
@@ -596,7 +596,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
                 variant_index: _,
             } => {
                 self.mutate_place(
-                    ContextKind::SetDiscrim.new(location),
+                    location,
                     (place, span),
                     Shallow(None),
                     JustWrite,
@@ -604,27 +604,26 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
                 );
             }
             StatementKind::InlineAsm(ref asm) => {
-                let context = ContextKind::InlineAsm.new(location);
                 for (o, output) in asm.asm.outputs.iter().zip(asm.outputs.iter()) {
                     if o.is_indirect {
                         // FIXME(eddyb) indirect inline asm outputs should
                         // be encoded through MIR place derefs instead.
                         self.access_place(
-                            context,
+                            location,
                             (output, o.span),
                             (Deep, Read(ReadKind::Copy)),
                             LocalMutationIsAllowed::No,
                             flow_state,
                         );
                         self.check_if_path_or_subpath_is_moved(
-                            context,
+                            location,
                             InitializationRequiringAction::Use,
                             (output, o.span),
                             flow_state,
                         );
                     } else {
                         self.mutate_place(
-                            context,
+                            location,
                             (output, o.span),
                             if o.is_rw { Deep } else { Shallow(None) },
                             if o.is_rw { WriteAndRead } else { JustWrite },
@@ -633,7 +632,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
                     }
                 }
                 for (_, input) in asm.inputs.iter() {
-                    self.consume_operand(context, (input, span), flow_state);
+                    self.consume_operand(location, (input, span), flow_state);
                 }
             }
             StatementKind::Nop
@@ -645,7 +644,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
             }
             StatementKind::StorageDead(local) => {
                 self.access_place(
-                    ContextKind::StorageDead.new(location),
+                    location,
                     (&Place::Base(PlaceBase::Local(local)), span),
                     (Shallow(None), Write(WriteKind::StorageDeadOrDrop)),
                     LocalMutationIsAllowed::Yes,
@@ -677,7 +676,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
                 values: _,
                 targets: _,
             } => {
-                self.consume_operand(ContextKind::SwitchInt.new(loc), (discr, span), flow_state);
+                self.consume_operand(loc, (discr, span), flow_state);
             }
             TerminatorKind::Drop {
                 location: ref drop_place,
@@ -702,7 +701,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
                        loc, term, drop_place, drop_place_ty, span);
 
                 self.access_place(
-                    ContextKind::Drop.new(loc),
+                    loc,
                     (drop_place, span),
                     (AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)),
                     LocalMutationIsAllowed::Yes,
@@ -716,14 +715,14 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
                 unwind: _,
             } => {
                 self.mutate_place(
-                    ContextKind::DropAndReplace.new(loc),
+                    loc,
                     (drop_place, span),
                     Deep,
                     JustWrite,
                     flow_state,
                 );
                 self.consume_operand(
-                    ContextKind::DropAndReplace.new(loc),
+                    loc,
                     (new_value, span),
                     flow_state,
                 );
@@ -735,17 +734,17 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
                 cleanup: _,
                 from_hir_call: _,
             } => {
-                self.consume_operand(ContextKind::CallOperator.new(loc), (func, span), flow_state);
+                self.consume_operand(loc, (func, span), flow_state);
                 for arg in args {
                     self.consume_operand(
-                        ContextKind::CallOperand.new(loc),
+                        loc,
                         (arg, span),
                         flow_state,
                     );
                 }
                 if let Some((ref dest, _ /*bb*/)) = *destination {
                     self.mutate_place(
-                        ContextKind::CallDest.new(loc),
+                        loc,
                         (dest, span),
                         Deep,
                         JustWrite,
@@ -760,11 +759,11 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
                 target: _,
                 cleanup: _,
             } => {
-                self.consume_operand(ContextKind::Assert.new(loc), (cond, span), flow_state);
+                self.consume_operand(loc, (cond, span), flow_state);
                 use rustc::mir::interpret::InterpError::BoundsCheck;
                 if let BoundsCheck { ref len, ref index } = *msg {
-                    self.consume_operand(ContextKind::Assert.new(loc), (len, span), flow_state);
-                    self.consume_operand(ContextKind::Assert.new(loc), (index, span), flow_state);
+                    self.consume_operand(loc, (len, span), flow_state);
+                    self.consume_operand(loc, (index, span), flow_state);
                 }
             }
 
@@ -773,7 +772,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
                 resume: _,
                 drop: _,
             } => {
-                self.consume_operand(ContextKind::Yield.new(loc), (value, span), flow_state);
+                self.consume_operand(loc, (value, span), flow_state);
 
                 if self.movable_generator {
                     // Look for any active borrows to locals
@@ -796,8 +795,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
                 flow_state.with_outgoing_borrows(|borrows| {
                     for i in borrows {
                         let borrow = &borrow_set[i];
-                        let context = ContextKind::StorageDead.new(loc);
-                        self.check_for_invalidation_at_exit(context, borrow, span);
+                        self.check_for_invalidation_at_exit(loc, borrow, span);
                     }
                 });
             }
@@ -955,7 +953,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
     /// Returns `true` if an error is reported.
     fn access_place(
         &mut self,
-        context: Context,
+        location: Location,
         place_span: (&Place<'tcx>, Span),
         kind: (AccessDepth, ReadOrWrite),
         is_local_mutation_allowed: LocalMutationIsAllowed,
@@ -994,10 +992,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                 rw,
                 is_local_mutation_allowed,
                 flow_state,
-                context.loc,
+                location,
             );
         let conflict_error =
-            self.check_access_for_conflict(context, place_span, sd, rw, flow_state);
+            self.check_access_for_conflict(location, place_span, sd, rw, flow_state);
 
         if let (Activation(_, borrow_idx), true) = (kind.1, conflict_error) {
             // Suppress this warning when there's an error being emited for the
@@ -1018,30 +1016,30 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
 
     fn check_access_for_conflict(
         &mut self,
-        context: Context,
+        location: Location,
         place_span: (&Place<'tcx>, Span),
         sd: AccessDepth,
         rw: ReadOrWrite,
         flow_state: &Flows<'cx, 'gcx, 'tcx>,
     ) -> bool {
         debug!(
-            "check_access_for_conflict(context={:?}, place_span={:?}, sd={:?}, rw={:?})",
-            context, place_span, sd, rw,
+            "check_access_for_conflict(location={:?}, place_span={:?}, sd={:?}, rw={:?})",
+            location, place_span, sd, rw,
         );
 
         let mut error_reported = false;
         let tcx = self.infcx.tcx;
         let mir = self.mir;
-        let location = self.location_table.start_index(context.loc);
+        let location_table = self.location_table.start_index(location);
         let borrow_set = self.borrow_set.clone();
         each_borrow_involving_path(
             self,
             tcx,
             mir,
-            context,
+            location,
             (sd, place_span.0),
             &borrow_set,
-            flow_state.borrows_in_scope(location),
+            flow_state.borrows_in_scope(location_table),
             |this, borrow_index, borrow| match (rw, borrow.kind) {
                 // Obviously an activation is compatible with its own
                 // reservation (or even prior activating uses of same
@@ -1075,7 +1073,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
 
                 (Read(kind), BorrowKind::Unique) | (Read(kind), BorrowKind::Mut { .. }) => {
                     // Reading from mere reservations of mutable-borrows is OK.
-                    if !is_active(&this.dominators, borrow, context.loc) {
+                    if !is_active(&this.dominators, borrow, location) {
                         assert!(allow_two_phase_borrow(borrow.kind));
                         return Control::Continue;
                     }
@@ -1083,11 +1081,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                     error_reported = true;
                     match kind {
                         ReadKind::Copy  => {
-                            this.report_use_while_mutably_borrowed(context, place_span, borrow)
+                            this.report_use_while_mutably_borrowed(location, place_span, borrow)
                                 .buffer(&mut this.errors_buffer);
                         }
                         ReadKind::Borrow(bk) => {
-                            this.report_conflicting_borrow(context, place_span, bk, borrow)
+                            this.report_conflicting_borrow(location, place_span, bk, borrow)
                                 .buffer(&mut this.errors_buffer);
                         }
                     }
@@ -1098,7 +1096,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                 | (Reservation(WriteKind::MutableBorrow(bk)), BorrowKind::Shared) if {
                     tcx.migrate_borrowck()
                 } => {
-                    let bi = this.borrow_set.location_map[&context.loc];
+                    let bi = this.borrow_set.location_map[&location];
                     debug!(
                         "recording invalid reservation of place: {:?} with \
                          borrow index {:?} as warning",
@@ -1111,7 +1109,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                     // checking was otherwise successful.
                     this.reservation_warnings.insert(
                         bi,
-                        (place_span.0.clone(), place_span.1, context, bk, borrow.clone()),
+                        (place_span.0.clone(), place_span.1, location, bk, borrow.clone()),
                     );
 
                     // Don't suppress actual errors.
@@ -1143,21 +1141,21 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                     error_reported = true;
                     match kind {
                         WriteKind::MutableBorrow(bk) => {
-                            this.report_conflicting_borrow(context, place_span, bk, borrow)
+                            this.report_conflicting_borrow(location, place_span, bk, borrow)
                                 .buffer(&mut this.errors_buffer);
                         }
                         WriteKind::StorageDeadOrDrop => {
                             this.report_borrowed_value_does_not_live_long_enough(
-                                context,
+                                location,
                                 borrow,
                                 place_span,
                                 Some(kind))
                         }
                         WriteKind::Mutate => {
-                            this.report_illegal_mutation_of_borrowed(context, place_span, borrow)
+                            this.report_illegal_mutation_of_borrowed(location, place_span, borrow)
                         }
                         WriteKind::Move => {
-                            this.report_move_out_while_borrowed(context, place_span, borrow)
+                            this.report_move_out_while_borrowed(location, place_span, borrow)
                         }
                     }
                     Control::Break
@@ -1170,7 +1168,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
 
     fn mutate_place(
         &mut self,
-        context: Context,
+        location: Location,
         place_span: (&Place<'tcx>, Span),
         kind: AccessDepth,
         mode: MutateMode,
@@ -1180,14 +1178,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         match mode {
             MutateMode::WriteAndRead => {
                 self.check_if_path_or_subpath_is_moved(
-                    context,
+                    location,
                     InitializationRequiringAction::Update,
                     place_span,
                     flow_state,
                 );
             }
             MutateMode::JustWrite => {
-                self.check_if_assigned_path_is_moved(context, place_span, flow_state);
+                self.check_if_assigned_path_is_moved(location, place_span, flow_state);
             }
         }
 
@@ -1198,7 +1196,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             if let Mutability::Not = self.mir.local_decls[local].mutability {
                 // check for reassignments to immutable local variables
                 self.check_if_reassignment_to_immutable_state(
-                    context,
+                    location,
                     local,
                     place_span,
                     flow_state,
@@ -1209,7 +1207,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
 
         // Otherwise, use the normal access permission rules.
         self.access_place(
-            context,
+            location,
             place_span,
             (kind, Write(WriteKind::Mutate)),
             LocalMutationIsAllowed::No,
@@ -1219,9 +1217,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
 
     fn consume_rvalue(
         &mut self,
-        context: Context,
+        location: Location,
         (rvalue, span): (&Rvalue<'tcx>, Span),
-        _location: Location,
         flow_state: &Flows<'cx, 'gcx, 'tcx>,
     ) {
         match *rvalue {
@@ -1242,7 +1239,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                 };
 
                 self.access_place(
-                    context,
+                    location,
                     (place, span),
                     access_kind,
                     LocalMutationIsAllowed::No,
@@ -1256,7 +1253,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                 };
 
                 self.check_if_path_or_subpath_is_moved(
-                    context,
+                    location,
                     action,
                     (place, span),
                     flow_state,
@@ -1267,7 +1264,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             | Rvalue::Repeat(ref operand, _)
             | Rvalue::UnaryOp(_ /*un_op*/, ref operand)
             | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) => {
-                self.consume_operand(context, (operand, span), flow_state)
+                self.consume_operand(location, (operand, span), flow_state)
             }
 
             Rvalue::Len(ref place) | Rvalue::Discriminant(ref place) => {
@@ -1277,14 +1274,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                     _ => unreachable!(),
                 };
                 self.access_place(
-                    context,
+                    location,
                     (place, span),
                     (Shallow(af), Read(ReadKind::Copy)),
                     LocalMutationIsAllowed::No,
                     flow_state,
                 );
                 self.check_if_path_or_subpath_is_moved(
-                    context,
+                    location,
                     InitializationRequiringAction::Use,
                     (place, span),
                     flow_state,
@@ -1293,8 +1290,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
 
             Rvalue::BinaryOp(_bin_op, ref operand1, ref operand2)
             | Rvalue::CheckedBinaryOp(_bin_op, ref operand1, ref operand2) => {
-                self.consume_operand(context, (operand1, span), flow_state);
-                self.consume_operand(context, (operand2, span), flow_state);
+                self.consume_operand(location, (operand1, span), flow_state);
+                self.consume_operand(location, (operand2, span), flow_state);
             }
 
             Rvalue::NullaryOp(_op, _ty) => {
@@ -1326,7 +1323,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                 }
 
                 for operand in operands {
-                    self.consume_operand(context, (operand, span), flow_state);
+                    self.consume_operand(location, (operand, span), flow_state);
                 }
             }
         }
@@ -1407,7 +1404,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
 
     fn consume_operand(
         &mut self,
-        context: Context,
+        location: Location,
         (operand, span): (&Operand<'tcx>, Span),
         flow_state: &Flows<'cx, 'gcx, 'tcx>,
     ) {
@@ -1416,7 +1413,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                 // copy of place: check if this is "copy of frozen path"
                 // (FIXME: see check_loans.rs)
                 self.access_place(
-                    context,
+                    location,
                     (place, span),
                     (Deep, Read(ReadKind::Copy)),
                     LocalMutationIsAllowed::No,
@@ -1425,7 +1422,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
 
                 // Finally, check if path was already moved.
                 self.check_if_path_or_subpath_is_moved(
-                    context,
+                    location,
                     InitializationRequiringAction::Use,
                     (place, span),
                     flow_state,
@@ -1434,7 +1431,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             Operand::Move(ref place) => {
                 // move of place: check if this is move of already borrowed path
                 self.access_place(
-                    context,
+                    location,
                     (place, span),
                     (Deep, Write(WriteKind::Move)),
                     LocalMutationIsAllowed::Yes,
@@ -1443,7 +1440,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
 
                 // Finally, check if path was already moved.
                 self.check_if_path_or_subpath_is_moved(
-                    context,
+                    location,
                     InitializationRequiringAction::Use,
                     (place, span),
                     flow_state,
@@ -1457,7 +1454,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
     /// exits
     fn check_for_invalidation_at_exit(
         &mut self,
-        context: Context,
+        location: Location,
         borrow: &BorrowData<'tcx>,
         span: Span,
     ) {
@@ -1513,7 +1510,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             // of just a span here.
             let span = self.infcx.tcx.sess.source_map().end_point(span);
             self.report_borrowed_value_does_not_live_long_enough(
-                context,
+                location,
                 borrow,
                 (place, span),
                 None,
@@ -1558,7 +1555,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             });
 
             self.access_place(
-                ContextKind::Activation.new(location),
+                location,
                 (&borrow.borrowed_place, span),
                 (
                     Deep,
@@ -1577,7 +1574,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
     fn check_if_reassignment_to_immutable_state(
         &mut self,
-        context: Context,
+        location: Location,
         local: Local,
         place_span: (&Place<'tcx>, Span),
         flow_state: &Flows<'cx, 'gcx, 'tcx>,
@@ -1590,14 +1587,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             let init = &self.move_data.inits[init_index];
             let span = init.span(&self.mir);
             self.report_illegal_reassignment(
-                context, place_span, span, place_span.0
+                location, place_span, span, place_span.0
             );
         }
     }
 
     fn check_if_full_path_is_moved(
         &mut self,
-        context: Context,
+        location: Location,
         desired_action: InitializationRequiringAction,
         place_span: (&Place<'tcx>, Span),
         flow_state: &Flows<'cx, 'gcx, 'tcx>,
@@ -1644,7 +1641,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             Ok((prefix, mpi)) => {
                 if maybe_uninits.contains(mpi) {
                     self.report_use_of_moved_or_uninitialized(
-                        context,
+                        location,
                         desired_action,
                         (prefix, place_span.0, place_span.1),
                         mpi,
@@ -1665,7 +1662,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
 
     fn check_if_path_or_subpath_is_moved(
         &mut self,
-        context: Context,
+        location: Location,
         desired_action: InitializationRequiringAction,
         place_span: (&Place<'tcx>, Span),
         flow_state: &Flows<'cx, 'gcx, 'tcx>,
@@ -1687,7 +1684,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         //    must have been initialized for the use to be sound.
         // 6. Move of `a.b.c` then reinit of `a.b.c.d`, use of `a.b.c.d`
 
-        self.check_if_full_path_is_moved(context, desired_action, place_span, flow_state);
+        self.check_if_full_path_is_moved(location, desired_action, place_span, flow_state);
 
         // A move of any shallow suffix of `place` also interferes
         // with an attempt to use `place`. This is scenario 3 above.
@@ -1702,7 +1699,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         if let Some(mpi) = self.move_path_for_place(place_span.0) {
             if let Some(child_mpi) = maybe_uninits.has_any_child_of(mpi) {
                 self.report_use_of_moved_or_uninitialized(
-                    context,
+                    location,
                     desired_action,
                     (place_span.0, place_span.0, place_span.1),
                     child_mpi,
@@ -1753,7 +1750,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
 
     fn check_if_assigned_path_is_moved(
         &mut self,
-        context: Context,
+        location: Location,
         (place, span): (&Place<'tcx>, Span),
         flow_state: &Flows<'cx, 'gcx, 'tcx>,
     ) {
@@ -1781,7 +1778,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                         // assigning to (*P) requires P to be initialized
                         ProjectionElem::Deref => {
                             self.check_if_full_path_is_moved(
-                                context, InitializationRequiringAction::Use,
+                                location, InitializationRequiringAction::Use,
                                 (base, span), flow_state);
                             // (base initialized; no need to
                             // recur further)
@@ -1789,8 +1786,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                         }
 
                         ProjectionElem::Subslice { .. } => {
-                            panic!("we don't allow assignments to subslices, context: {:?}",
-                                   context);
+                            panic!("we don't allow assignments to subslices, location: {:?}",
+                                   location);
                         }
 
                         ProjectionElem::Field(..) => {
@@ -1801,7 +1798,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                             match base.ty(self.mir, tcx).ty.sty {
                                 ty::Adt(def, _) if def.has_dtor(tcx) => {
                                     self.check_if_path_or_subpath_is_moved(
-                                        context, InitializationRequiringAction::Assignment,
+                                        location, InitializationRequiringAction::Assignment,
                                         (base, span), flow_state);
 
                                     // (base initialized; no need to
@@ -1813,7 +1810,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                                 // Once `let s; s.x = V; read(s.x);`,
                                 // is allowed, remove this match arm.
                                 ty::Adt(..) | ty::Tuple(..) => {
-                                    check_parent_of_field(self, context, base, span, flow_state);
+                                    check_parent_of_field(self, location, base, span, flow_state);
 
                                     if let Some(local) = place.base_local() {
                                         // rust-lang/rust#21232,
@@ -1841,7 +1838,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
 
         fn check_parent_of_field<'cx, 'gcx, 'tcx>(
             this: &mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>,
-            context: Context,
+            location: Location,
             base: &Place<'tcx>,
             span: Span,
             flow_state: &Flows<'cx, 'gcx, 'tcx>,
@@ -1907,7 +1904,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                     if def.is_union() {
                         if this.move_data.path_map[mpi].iter().any(|moi| {
                             this.move_data.moves[*moi].source.is_predecessor_of(
-                                context.loc, this.mir,
+                                location, this.mir,
                             )
                         }) {
                             return;
@@ -1916,7 +1913,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                 }
 
                 this.report_use_of_moved_or_uninitialized(
-                    context,
+                    location,
                     InitializationRequiringAction::PartialAssignment,
                     (prefix, base, span),
                     mpi,
@@ -2234,7 +2231,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                                     // Subtle: this is an upvar
                                     // reference, so it looks like
                                     // `self.foo` -- we want to double
-                                    // check that the context `*self`
+                                    // check that the location `*self`
                                     // is mutable (i.e., this is not a
                                     // `Fn` closure).  But if that
                                     // check succeeds, we want to
@@ -2331,37 +2328,3 @@ enum Overlap {
     /// will also be disjoint.
     Disjoint,
 }
-
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-struct Context {
-    kind: ContextKind,
-    loc: Location,
-}
-
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-enum ContextKind {
-    Activation,
-    AssignLhs,
-    AssignRhs,
-    SetDiscrim,
-    InlineAsm,
-    SwitchInt,
-    Drop,
-    DropAndReplace,
-    CallOperator,
-    CallOperand,
-    CallDest,
-    Assert,
-    Yield,
-    FakeRead,
-    StorageDead,
-}
-
-impl ContextKind {
-    fn new(self, loc: Location) -> Context {
-        Context {
-            kind: self,
-            loc,
-        }
-    }
-}
diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
index 89f85a941d3..c64d4b4a531 100644
--- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
@@ -4,7 +4,7 @@ use crate::borrow_check::borrow_set::BorrowData;
 use crate::borrow_check::error_reporting::UseSpans;
 use crate::borrow_check::nll::region_infer::{Cause, RegionName};
 use crate::borrow_check::nll::ConstraintDescription;
-use crate::borrow_check::{Context, MirBorrowckCtxt, WriteKind};
+use crate::borrow_check::{MirBorrowckCtxt, WriteKind};
 use rustc::mir::{
     CastKind, ConstraintCategory, FakeReadCause, Local, Location, Mir, Operand, Place, PlaceBase,
     Projection, ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind,
@@ -209,13 +209,13 @@ impl BorrowExplanation {
 
 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
     /// Returns structured explanation for *why* the borrow contains the
-    /// point from `context`. This is key for the "3-point errors"
+    /// point from `location`. This is key for the "3-point errors"
     /// [described in the NLL RFC][d].
     ///
     /// # Parameters
     ///
     /// - `borrow`: the borrow in question
-    /// - `context`: where the borrow occurs
+    /// - `location`: where the borrow occurs
     /// - `kind_place`: if Some, this describes the statement that triggered the error.
     ///   - first half is the kind of write, if any, being performed
     ///   - second half is the place being accessed
@@ -223,13 +223,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
     /// [d]: https://rust-lang.github.io/rfcs/2094-nll.html#leveraging-intuition-framing-errors-in-terms-of-points
     pub(in crate::borrow_check) fn explain_why_borrow_contains_point(
         &self,
-        context: Context,
+        location: Location,
         borrow: &BorrowData<'tcx>,
         kind_place: Option<(WriteKind, &Place<'tcx>)>,
     ) -> BorrowExplanation {
         debug!(
-            "explain_why_borrow_contains_point(context={:?}, borrow={:?}, kind_place={:?})",
-            context, borrow, kind_place
+            "explain_why_borrow_contains_point(location={:?}, borrow={:?}, kind_place={:?})",
+            location, borrow, kind_place
         );
 
         let regioncx = &self.nonlexical_regioncx;
@@ -242,20 +242,20 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             borrow_region_vid
         );
 
-        let region_sub = regioncx.find_sub_region_live_at(borrow_region_vid, context.loc);
+        let region_sub = regioncx.find_sub_region_live_at(borrow_region_vid, location);
         debug!(
             "explain_why_borrow_contains_point: region_sub={:?}",
             region_sub
         );
 
-        match find_use::find(mir, regioncx, tcx, region_sub, context.loc) {
+        match find_use::find(mir, regioncx, tcx, region_sub, location) {
             Some(Cause::LiveVar(local, location)) => {
                 let span = mir.source_info(location).span;
                 let spans = self
                     .move_spans(&Place::Base(PlaceBase::Local(local)), location)
                     .or_else(|| self.borrow_spans(span, location));
 
-                let borrow_location = context.loc;
+                let borrow_location = location;
                 if self.is_use_in_later_iteration_of_loop(borrow_location, location) {
                     let later_use = self.later_use_kind(borrow, spans, location);
                     BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1)
diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/nll/invalidation.rs
index fd17d4a8125..e3ab48ccff1 100644
--- a/src/librustc_mir/borrow_check/nll/invalidation.rs
+++ b/src/librustc_mir/borrow_check/nll/invalidation.rs
@@ -3,7 +3,6 @@ use crate::borrow_check::location::LocationTable;
 use crate::borrow_check::{JustWrite, WriteAndRead};
 use crate::borrow_check::{AccessDepth, Deep, Shallow};
 use crate::borrow_check::{ReadOrWrite, Activation, Read, Reservation, Write};
-use crate::borrow_check::{Context, ContextKind};
 use crate::borrow_check::{LocalMutationIsAllowed, MutateMode};
 use crate::borrow_check::ArtificialField;
 use crate::borrow_check::{ReadKind, WriteKind};
@@ -66,12 +65,12 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> {
         match statement.kind {
             StatementKind::Assign(ref lhs, ref rhs) => {
                 self.consume_rvalue(
-                    ContextKind::AssignRhs.new(location),
+                    location,
                     rhs,
                 );
 
                 self.mutate_place(
-                    ContextKind::AssignLhs.new(location),
+                    location,
                     lhs,
                     Shallow(None),
                     JustWrite
@@ -85,27 +84,26 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> {
                 variant_index: _,
             } => {
                 self.mutate_place(
-                    ContextKind::SetDiscrim.new(location),
+                    location,
                     place,
                     Shallow(None),
                     JustWrite,
                 );
             }
             StatementKind::InlineAsm(ref asm) => {
-                let context = ContextKind::InlineAsm.new(location);
                 for (o, output) in asm.asm.outputs.iter().zip(asm.outputs.iter()) {
                     if o.is_indirect {
                         // FIXME(eddyb) indirect inline asm outputs should
                         // be encoded through MIR place derefs instead.
                         self.access_place(
-                            context,
+                            location,
                             output,
                             (Deep, Read(ReadKind::Copy)),
                             LocalMutationIsAllowed::No,
                         );
                     } else {
                         self.mutate_place(
-                            context,
+                            location,
                             output,
                             if o.is_rw { Deep } else { Shallow(None) },
                             if o.is_rw { WriteAndRead } else { JustWrite },
@@ -113,7 +111,7 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> {
                     }
                 }
                 for (_, input) in asm.inputs.iter() {
-                    self.consume_operand(context, input);
+                    self.consume_operand(location, input);
                 }
             }
             StatementKind::Nop |
@@ -125,7 +123,7 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> {
             }
             StatementKind::StorageDead(local) => {
                 self.access_place(
-                    ContextKind::StorageDead.new(location),
+                    location,
                     &Place::Base(PlaceBase::Local(local)),
                     (Shallow(None), Write(WriteKind::StorageDeadOrDrop)),
                     LocalMutationIsAllowed::Yes,
@@ -150,7 +148,7 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> {
                 values: _,
                 targets: _,
             } => {
-                self.consume_operand(ContextKind::SwitchInt.new(location), discr);
+                self.consume_operand(location, discr);
             }
             TerminatorKind::Drop {
                 location: ref drop_place,
@@ -158,7 +156,7 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> {
                 unwind: _,
             } => {
                 self.access_place(
-                    ContextKind::Drop.new(location),
+                    location,
                     drop_place,
                     (AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)),
                     LocalMutationIsAllowed::Yes,
@@ -171,13 +169,13 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> {
                 unwind: _,
             } => {
                 self.mutate_place(
-                    ContextKind::DropAndReplace.new(location),
+                    location,
                     drop_place,
                     Deep,
                     JustWrite,
                 );
                 self.consume_operand(
-                    ContextKind::DropAndReplace.new(location),
+                    location,
                     new_value,
                 );
             }
@@ -188,13 +186,13 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> {
                 cleanup: _,
                 from_hir_call: _,
             } => {
-                self.consume_operand(ContextKind::CallOperator.new(location), func);
+                self.consume_operand(location, func);
                 for arg in args {
-                    self.consume_operand(ContextKind::CallOperand.new(location), arg);
+                    self.consume_operand(location, arg);
                 }
                 if let Some((ref dest, _ /*bb*/)) = *destination {
                     self.mutate_place(
-                        ContextKind::CallDest.new(location),
+                        location,
                         dest,
                         Deep,
                         JustWrite,
@@ -208,11 +206,11 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> {
                 target: _,
                 cleanup: _,
             } => {
-                self.consume_operand(ContextKind::Assert.new(location), cond);
+                self.consume_operand(location, cond);
                 use rustc::mir::interpret::InterpError::BoundsCheck;
                 if let BoundsCheck { ref len, ref index } = *msg {
-                    self.consume_operand(ContextKind::Assert.new(location), len);
-                    self.consume_operand(ContextKind::Assert.new(location), index);
+                    self.consume_operand(location, len);
+                    self.consume_operand(location, index);
                 }
             }
             TerminatorKind::Yield {
@@ -220,7 +218,7 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> {
                 resume,
                 drop: _,
             } => {
-                self.consume_operand(ContextKind::Yield.new(location), value);
+                self.consume_operand(location, value);
 
                 // Invalidate all borrows of local places
                 let borrow_set = self.borrow_set.clone();
@@ -264,13 +262,13 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
     /// Simulates mutation of a place.
     fn mutate_place(
         &mut self,
-        context: Context,
+        location: Location,
         place: &Place<'tcx>,
         kind: AccessDepth,
         _mode: MutateMode,
     ) {
         self.access_place(
-            context,
+            location,
             place,
             (kind, Write(WriteKind::Mutate)),
             LocalMutationIsAllowed::ExceptUpvars,
@@ -280,13 +278,13 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
     /// Simulates consumption of an operand.
     fn consume_operand(
         &mut self,
-        context: Context,
+        location: Location,
         operand: &Operand<'tcx>,
     ) {
         match *operand {
             Operand::Copy(ref place) => {
                 self.access_place(
-                    context,
+                    location,
                     place,
                     (Deep, Read(ReadKind::Copy)),
                     LocalMutationIsAllowed::No,
@@ -294,7 +292,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
             }
             Operand::Move(ref place) => {
                 self.access_place(
-                    context,
+                    location,
                     place,
                     (Deep, Write(WriteKind::Move)),
                     LocalMutationIsAllowed::Yes,
@@ -307,7 +305,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
     // Simulates consumption of an rvalue
     fn consume_rvalue(
         &mut self,
-        context: Context,
+        location: Location,
         rvalue: &Rvalue<'tcx>,
     ) {
         match *rvalue {
@@ -328,7 +326,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
                 };
 
                 self.access_place(
-                    context,
+                    location,
                     place,
                     access_kind,
                     LocalMutationIsAllowed::No,
@@ -339,7 +337,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
             | Rvalue::Repeat(ref operand, _)
             | Rvalue::UnaryOp(_ /*un_op*/, ref operand)
             | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) => {
-                self.consume_operand(context, operand)
+                self.consume_operand(location, operand)
             }
 
             Rvalue::Len(ref place) | Rvalue::Discriminant(ref place) => {
@@ -349,7 +347,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
                     _ => unreachable!(),
                 };
                 self.access_place(
-                    context,
+                    location,
                     place,
                     (Shallow(af), Read(ReadKind::Copy)),
                     LocalMutationIsAllowed::No,
@@ -358,8 +356,8 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
 
             Rvalue::BinaryOp(_bin_op, ref operand1, ref operand2)
             | Rvalue::CheckedBinaryOp(_bin_op, ref operand1, ref operand2) => {
-                self.consume_operand(context, operand1);
-                self.consume_operand(context, operand2);
+                self.consume_operand(location, operand1);
+                self.consume_operand(location, operand2);
             }
 
             Rvalue::NullaryOp(_op, _ty) => {
@@ -367,7 +365,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
 
             Rvalue::Aggregate(_, ref operands) => {
                 for operand in operands {
-                    self.consume_operand(context, operand);
+                    self.consume_operand(location, operand);
                 }
             }
         }
@@ -376,27 +374,27 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
     /// Simulates an access to a place.
     fn access_place(
         &mut self,
-        context: Context,
+        location: Location,
         place: &Place<'tcx>,
         kind: (AccessDepth, ReadOrWrite),
         _is_local_mutation_allowed: LocalMutationIsAllowed,
     ) {
         let (sd, rw) = kind;
         // note: not doing check_access_permissions checks because they don't generate invalidates
-        self.check_access_for_conflict(context, place, sd, rw);
+        self.check_access_for_conflict(location, place, sd, rw);
     }
 
     fn check_access_for_conflict(
         &mut self,
-        context: Context,
+        location: Location,
         place: &Place<'tcx>,
         sd: AccessDepth,
         rw: ReadOrWrite,
     ) {
         debug!(
-            "invalidation::check_access_for_conflict(context={:?}, place={:?}, sd={:?}, \
+            "invalidation::check_access_for_conflict(location={:?}, place={:?}, sd={:?}, \
              rw={:?})",
-            context,
+            location,
             place,
             sd,
             rw,
@@ -409,7 +407,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
             self,
             tcx,
             mir,
-            context,
+            location,
             (sd, place),
             &borrow_set.clone(),
             indices,
@@ -435,7 +433,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
 
                     (Read(_), BorrowKind::Unique) | (Read(_), BorrowKind::Mut { .. }) => {
                         // Reading from mere reservations of mutable-borrows is OK.
-                        if !is_active(&this.dominators, borrow, context.loc) {
+                        if !is_active(&this.dominators, borrow, location) {
                             // If the borrow isn't active yet, reads don't invalidate it
                             assert!(allow_two_phase_borrow(borrow.kind));
                             return Control::Continue;
@@ -443,7 +441,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
 
                         // Unique and mutable borrows are invalidated by reads from any
                         // involved path
-                        this.generate_invalidates(borrow_index, context.loc);
+                        this.generate_invalidates(borrow_index, location);
                     }
 
                     (Reservation(_), _)
@@ -453,7 +451,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
                         // Reservations count as writes since we need to check
                         // that activating the borrow will be OK
                         // FIXME(bob_twinkles) is this actually the right thing to do?
-                        this.generate_invalidates(borrow_index, context.loc);
+                        this.generate_invalidates(borrow_index, location);
                     }
                 }
                 Control::Continue
@@ -485,7 +483,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
             });
 
             self.access_place(
-                ContextKind::Activation.new(location),
+                location,
                 &borrow.borrowed_place,
                 (
                     Deep,
diff --git a/src/librustc_mir/borrow_check/path_utils.rs b/src/librustc_mir/borrow_check/path_utils.rs
index 86af2490408..0c2a4ef45f1 100644
--- a/src/librustc_mir/borrow_check/path_utils.rs
+++ b/src/librustc_mir/borrow_check/path_utils.rs
@@ -1,6 +1,5 @@
 use crate::borrow_check::borrow_set::{BorrowSet, BorrowData, TwoPhaseActivation};
 use crate::borrow_check::places_conflict;
-use crate::borrow_check::Context;
 use crate::borrow_check::AccessDepth;
 use crate::dataflow::indexes::BorrowIndex;
 use rustc::mir::{BasicBlock, Location, Mir, Place, PlaceBase};
@@ -27,7 +26,7 @@ pub(super) fn each_borrow_involving_path<'a, 'tcx, 'gcx: 'tcx, F, I, S> (
     s: &mut S,
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
     mir: &Mir<'tcx>,
-    _context: Context,
+    _location: Location,
     access_place: (AccessDepth, &Place<'tcx>),
     borrow_set: &BorrowSet<'tcx>,
     candidates: I,
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index 4b8b3232bfa..681a204d76e 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -59,7 +59,7 @@ pub(crate) fn eval_promoted<'a, 'mir, 'tcx>(
 ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
     let span = tcx.def_span(cid.instance.def_id());
     let mut ecx = mk_eval_cx(tcx, span, param_env);
-    eval_body_using_ecx(&mut ecx, cid, Some(mir), param_env)
+    eval_body_using_ecx(&mut ecx, cid, mir, param_env)
 }
 
 fn mplace_to_const<'tcx>(
@@ -107,37 +107,15 @@ fn op_to_const<'tcx>(
     ty::Const { val, ty: op.layout.ty }
 }
 
-fn eval_body_and_ecx<'a, 'mir, 'tcx>(
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    cid: GlobalId<'tcx>,
-    mir: Option<&'mir mir::Mir<'tcx>>,
-    param_env: ty::ParamEnv<'tcx>,
-) -> (EvalResult<'tcx, MPlaceTy<'tcx>>, CompileTimeEvalContext<'a, 'mir, 'tcx>) {
-    // we start out with the best span we have
-    // and try improving it down the road when more information is available
-    let span = tcx.def_span(cid.instance.def_id());
-    let span = mir.map(|mir| mir.span).unwrap_or(span);
-    let mut ecx = InterpretCx::new(tcx.at(span), param_env, CompileTimeInterpreter::new());
-    let r = eval_body_using_ecx(&mut ecx, cid, mir, param_env);
-    (r, ecx)
-}
-
 // Returns a pointer to where the result lives
 fn eval_body_using_ecx<'mir, 'tcx>(
     ecx: &mut CompileTimeEvalContext<'_, 'mir, 'tcx>,
     cid: GlobalId<'tcx>,
-    mir: Option<&'mir mir::Mir<'tcx>>,
+    mir: &'mir mir::Mir<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
 ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
     debug!("eval_body_using_ecx: {:?}, {:?}", cid, param_env);
     let tcx = ecx.tcx.tcx;
-    let mut mir = match mir {
-        Some(mir) => mir,
-        None => ecx.load_mir(cid.instance.def)?,
-    };
-    if let Some(index) = cid.promoted {
-        mir = &mir.promoted[index];
-    }
     let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?;
     assert!(!layout.is_unsized());
     let ret = ecx.allocate(layout, MemoryKind::Stack);
@@ -618,8 +596,19 @@ pub fn const_eval_raw_provider<'a, 'tcx>(
         return Err(ErrorHandled::Reported);
     }
 
-    let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env);
-    res.and_then(|place| {
+    let span = tcx.def_span(cid.instance.def_id());
+    let mut ecx = InterpretCx::new(tcx.at(span), key.param_env, CompileTimeInterpreter::new());
+
+    let res = ecx.load_mir(cid.instance.def);
+    res.map(|mir| {
+        if let Some(index) = cid.promoted {
+            &mir.promoted[index]
+        } else {
+            mir
+        }
+    }).and_then(
+        |mir| eval_body_using_ecx(&mut ecx, cid, mir, key.param_env)
+    ).and_then(|place| {
         Ok(RawConst {
             alloc_id: place.to_ptr().expect("we allocated this ptr!").alloc_id,
             ty: place.layout.ty
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index 5ae052e46c5..2465adf46cd 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -301,7 +301,8 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
                 // cannot use `const_eval` here, because that would require having the MIR
                 // for the current function available, but we're producing said MIR right now
                 let res = self.use_ecx(source_info, |this| {
-                    eval_promoted(this.tcx, cid, this.mir, this.param_env)
+                    let mir = &this.mir.promoted[promoted];
+                    eval_promoted(this.tcx, cid, mir, this.param_env)
                 })?;
                 trace!("evaluated promoted {:?} to {:?}", promoted, res);
                 Some((res.into(), source_info.span))
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index be68f303537..dcfe00069c5 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -862,7 +862,13 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
         // Walk the generated async arguments if this is an `async fn`, otherwise walk the
         // normal arguments.
         if let IsAsync::Async { ref arguments, .. } = asyncness {
-            for a in arguments { add_argument(&a.arg); }
+            for (i, a) in arguments.iter().enumerate() {
+                if let Some(arg) = &a.arg {
+                    add_argument(&arg);
+                } else {
+                    add_argument(&declaration.inputs[i]);
+                }
+            }
         } else {
             for a in &declaration.inputs { add_argument(a); }
         }
@@ -882,8 +888,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
                     let mut body = body.clone();
                     // Insert the generated statements into the body before attempting to
                     // resolve names.
-                    for a in arguments {
-                        body.stmts.insert(0, a.stmt.clone());
+                    for a in arguments.iter().rev() {
+                        if let Some(pat_stmt) = a.pat_stmt.clone() {
+                            body.stmts.insert(0, pat_stmt);
+                        }
+                        body.stmts.insert(0, a.move_stmt.clone());
                     }
                     self.visit_block(&body);
                 } else {
@@ -4174,7 +4183,7 @@ impl<'a> Resolver<'a> {
         let add_module_candidates = |module: Module<'_>, names: &mut Vec<TypoSuggestion>| {
             for (&(ident, _), resolution) in module.resolutions.borrow().iter() {
                 if let Some(binding) = resolution.borrow().binding {
-                    if filter_fn(binding.def()) {
+                    if !ident.name.is_gensymed() && filter_fn(binding.def()) {
                         names.push(TypoSuggestion {
                             candidate: ident.name,
                             article: binding.def().article(),
@@ -4192,7 +4201,7 @@ impl<'a> Resolver<'a> {
             for rib in self.ribs[ns].iter().rev() {
                 // Locals and type parameters
                 for (ident, def) in &rib.bindings {
-                    if filter_fn(*def) {
+                    if !ident.name.is_gensymed() && filter_fn(*def) {
                         names.push(TypoSuggestion {
                             candidate: ident.name,
                             article: def.article(),
@@ -4219,7 +4228,7 @@ impl<'a> Resolver<'a> {
                                             index: CRATE_DEF_INDEX,
                                         });
 
-                                        if filter_fn(crate_mod) {
+                                        if !ident.name.is_gensymed() && filter_fn(crate_mod) {
                                             Some(TypoSuggestion {
                                                 candidate: ident.name,
                                                 article: "a",
@@ -4242,13 +4251,16 @@ impl<'a> Resolver<'a> {
             // Add primitive types to the mix
             if filter_fn(Def::PrimTy(Bool)) {
                 names.extend(
-                    self.primitive_type_table.primitive_types.iter().map(|(name, _)| {
-                        TypoSuggestion {
-                            candidate: *name,
-                            article: "a",
-                            kind: "primitive type",
-                        }
-                    })
+                    self.primitive_type_table.primitive_types
+                        .iter()
+                        .filter(|(name, _)| !name.is_gensymed())
+                        .map(|(name, _)| {
+                            TypoSuggestion {
+                                candidate: *name,
+                                article: "a",
+                                kind: "primitive type",
+                            }
+                        })
                 )
             }
         } else {
diff --git a/src/libstd/process.rs b/src/libstd/process.rs
index c1addb46a0a..6e4c6e4c366 100644
--- a/src/libstd/process.rs
+++ b/src/libstd/process.rs
@@ -134,6 +134,18 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
 /// the parent process wait until the child has actually exited before
 /// continuing.
 ///
+/// # Warning
+///
+/// On some system, calling [`wait`] or similar is necessary for the OS to
+/// release resources. A process that terminated but has not been waited on is
+/// still around as a "zombie". Leaving too many zombies around may exhaust
+/// global resources (for example process IDs).
+///
+/// The standard library does *not* automatically wait on child processes (not
+/// even if the `Child` is dropped), it is up to the application developer to do
+/// so. As a consequence, dropping `Child` handles without waiting on them first
+/// is not recommended in long-running applications.
+///
 /// # Examples
 ///
 /// ```should_panic
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index a20bf91a6ad..33b8c76bb53 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1865,10 +1865,14 @@ pub enum Unsafety {
 pub struct AsyncArgument {
     /// `__arg0`
     pub ident: Ident,
-    /// `__arg0: <ty>` argument to replace existing function argument `<pat>: <ty>`.
-    pub arg: Arg,
-    /// `let <pat>: <ty> = __arg0;` statement to be inserted at the start of the block.
-    pub stmt: Stmt,
+    /// `__arg0: <ty>` argument to replace existing function argument `<pat>: <ty>`. Only if
+    /// argument is not a simple binding.
+    pub arg: Option<Arg>,
+    /// `let __arg0 = __arg0;` statement to be inserted at the start of the block.
+    pub move_stmt: Stmt,
+    /// `let <pat> = __arg0;` statement to be inserted at the start of the block, after matching
+    /// move statement. Only if argument is not a simple binding.
+    pub pat_stmt: Option<Stmt>,
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
diff --git a/src/libsyntax/error_codes.rs b/src/libsyntax/error_codes.rs
index ac24475cab8..e2d212eb721 100644
--- a/src/libsyntax/error_codes.rs
+++ b/src/libsyntax/error_codes.rs
@@ -363,6 +363,35 @@ and likely to change in the future.
 
 "##,
 
+E0704: r##"
+This error indicates that a incorrect visibility restriction was specified.
+
+Example of erroneous code:
+
+```compile_fail,E0704
+mod foo {
+    pub(foo) struct Bar {
+        x: i32
+    }
+}
+```
+
+To make struct `Bar` only visible in module `foo` the `in` keyword should be
+used:
+```
+mod foo {
+    pub(in crate::foo) struct Bar {
+        x: i32
+    }
+}
+# fn main() {}
+```
+
+For more information see the Rust Reference on [Visibility].
+
+[Visibility]: https://doc.rust-lang.org/reference/visibility-and-privacy.html
+"##,
+
 E0705: r##"
 A `#![feature]` attribute was declared for a feature that is stable in
 the current edition, but not in all editions.
@@ -417,6 +446,5 @@ register_diagnostics! {
     E0693, // incorrect `repr(align)` attribute format
     E0694, // an unknown tool name found in scoped attributes
     E0703, // invalid ABI
-    E0704, // incorrect visibility restriction
     E0717, // rustc_promotable without stability attribute
 }
diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs
index 68cd3c28676..f5e18e98436 100644
--- a/src/libsyntax/ext/placeholders.rs
+++ b/src/libsyntax/ext/placeholders.rs
@@ -199,7 +199,10 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> {
 
         if let ast::IsAsync::Async { ref mut arguments, .. } = a {
             for argument in arguments.iter_mut() {
-                self.next_id(&mut argument.stmt.id);
+                self.next_id(&mut argument.move_stmt.id);
+                if let Some(ref mut pat_stmt) = &mut argument.pat_stmt {
+                    self.next_id(&mut pat_stmt.id);
+                }
             }
         }
     }
diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs
index d3441a2039b..2e09235ca77 100644
--- a/src/libsyntax/mut_visit.rs
+++ b/src/libsyntax/mut_visit.rs
@@ -694,13 +694,21 @@ pub fn noop_visit_asyncness<T: MutVisitor>(asyncness: &mut IsAsync, vis: &mut T)
         IsAsync::Async { closure_id, return_impl_trait_id, ref mut arguments } => {
             vis.visit_id(closure_id);
             vis.visit_id(return_impl_trait_id);
-            for AsyncArgument { ident, arg, stmt } in arguments.iter_mut() {
+            for AsyncArgument { ident, arg, pat_stmt, move_stmt } in arguments.iter_mut() {
                 vis.visit_ident(ident);
-                vis.visit_arg(arg);
-                visit_clobber(stmt, |stmt| {
+                if let Some(arg) = arg {
+                    vis.visit_arg(arg);
+                }
+                visit_clobber(move_stmt, |stmt| {
                     vis.flat_map_stmt(stmt)
                         .expect_one("expected visitor to produce exactly one item")
                 });
+                visit_opt(pat_stmt, |stmt| {
+                    visit_clobber(stmt, |stmt| {
+                        vis.flat_map_stmt(stmt)
+                            .expect_one("expected visitor to produce exactly one item")
+                    })
+                });
             }
         }
         IsAsync::NotAsync => {}
diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs
new file mode 100644
index 00000000000..32e1ee94f0d
--- /dev/null
+++ b/src/libsyntax/parse/diagnostics.rs
@@ -0,0 +1,226 @@
+use crate::ast;
+use crate::ast::{Expr, ExprKind, Item, ItemKind, Pat, PatKind, QSelf, Ty, TyKind};
+use crate::parse::parser::PathStyle;
+use crate::parse::token;
+use crate::parse::PResult;
+use crate::parse::Parser;
+use crate::print::pprust;
+use crate::ptr::P;
+use crate::ThinVec;
+use errors::Applicability;
+use syntax_pos::Span;
+
+pub trait RecoverQPath: Sized + 'static {
+    const PATH_STYLE: PathStyle = PathStyle::Expr;
+    fn to_ty(&self) -> Option<P<Ty>>;
+    fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self;
+}
+
+impl RecoverQPath for Ty {
+    const PATH_STYLE: PathStyle = PathStyle::Type;
+    fn to_ty(&self) -> Option<P<Ty>> {
+        Some(P(self.clone()))
+    }
+    fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
+        Self {
+            span: path.span,
+            node: TyKind::Path(qself, path),
+            id: ast::DUMMY_NODE_ID,
+        }
+    }
+}
+
+impl RecoverQPath for Pat {
+    fn to_ty(&self) -> Option<P<Ty>> {
+        self.to_ty()
+    }
+    fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
+        Self {
+            span: path.span,
+            node: PatKind::Path(qself, path),
+            id: ast::DUMMY_NODE_ID,
+        }
+    }
+}
+
+impl RecoverQPath for Expr {
+    fn to_ty(&self) -> Option<P<Ty>> {
+        self.to_ty()
+    }
+    fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
+        Self {
+            span: path.span,
+            node: ExprKind::Path(qself, path),
+            attrs: ThinVec::new(),
+            id: ast::DUMMY_NODE_ID,
+        }
+    }
+}
+
+impl<'a> Parser<'a> {
+    crate fn maybe_report_ambiguous_plus(
+        &mut self,
+        allow_plus: bool,
+        impl_dyn_multi: bool,
+        ty: &Ty,
+    ) {
+        if !allow_plus && impl_dyn_multi {
+            let sum_with_parens = format!("({})", pprust::ty_to_string(&ty));
+            self.struct_span_err(ty.span, "ambiguous `+` in a type")
+                .span_suggestion(
+                    ty.span,
+                    "use parentheses to disambiguate",
+                    sum_with_parens,
+                    Applicability::MachineApplicable,
+                )
+                .emit();
+        }
+    }
+
+    crate fn maybe_recover_from_bad_type_plus(
+        &mut self,
+        allow_plus: bool,
+        ty: &Ty,
+    ) -> PResult<'a, ()> {
+        // Do not add `+` to expected tokens.
+        if !allow_plus || !self.token.is_like_plus() {
+            return Ok(());
+        }
+
+        self.bump(); // `+`
+        let bounds = self.parse_generic_bounds(None)?;
+        let sum_span = ty.span.to(self.prev_span);
+
+        let mut err = struct_span_err!(
+            self.sess.span_diagnostic,
+            sum_span,
+            E0178,
+            "expected a path on the left-hand side of `+`, not `{}`",
+            pprust::ty_to_string(ty)
+        );
+
+        match ty.node {
+            TyKind::Rptr(ref lifetime, ref mut_ty) => {
+                let sum_with_parens = pprust::to_string(|s| {
+                    use crate::print::pprust::PrintState;
+
+                    s.s.word("&")?;
+                    s.print_opt_lifetime(lifetime)?;
+                    s.print_mutability(mut_ty.mutbl)?;
+                    s.popen()?;
+                    s.print_type(&mut_ty.ty)?;
+                    s.print_type_bounds(" +", &bounds)?;
+                    s.pclose()
+                });
+                err.span_suggestion(
+                    sum_span,
+                    "try adding parentheses",
+                    sum_with_parens,
+                    Applicability::MachineApplicable,
+                );
+            }
+            TyKind::Ptr(..) | TyKind::BareFn(..) => {
+                err.span_label(sum_span, "perhaps you forgot parentheses?");
+            }
+            _ => {
+                err.span_label(sum_span, "expected a path");
+            }
+        }
+        err.emit();
+        Ok(())
+    }
+
+    /// Try to recover from associated item paths like `[T]::AssocItem`/`(T, U)::AssocItem`.
+    /// Attempt to convert the base expression/pattern/type into a type, parse the `::AssocItem`
+    /// tail, and combine them into a `<Ty>::AssocItem` expression/pattern/type.
+    crate fn maybe_recover_from_bad_qpath<T: RecoverQPath>(
+        &mut self,
+        base: P<T>,
+        allow_recovery: bool,
+    ) -> PResult<'a, P<T>> {
+        // Do not add `::` to expected tokens.
+        if allow_recovery && self.token == token::ModSep {
+            if let Some(ty) = base.to_ty() {
+                return self.maybe_recover_from_bad_qpath_stage_2(ty.span, ty);
+            }
+        }
+        Ok(base)
+    }
+
+    /// Given an already parsed `Ty` parse the `::AssocItem` tail and
+    /// combine them into a `<Ty>::AssocItem` expression/pattern/type.
+    crate fn maybe_recover_from_bad_qpath_stage_2<T: RecoverQPath>(
+        &mut self,
+        ty_span: Span,
+        ty: P<Ty>,
+    ) -> PResult<'a, P<T>> {
+        self.expect(&token::ModSep)?;
+
+        let mut path = ast::Path {
+            segments: Vec::new(),
+            span: syntax_pos::DUMMY_SP,
+        };
+        self.parse_path_segments(&mut path.segments, T::PATH_STYLE)?;
+        path.span = ty_span.to(self.prev_span);
+
+        let ty_str = self
+            .sess
+            .source_map()
+            .span_to_snippet(ty_span)
+            .unwrap_or_else(|_| pprust::ty_to_string(&ty));
+        self.diagnostic()
+            .struct_span_err(path.span, "missing angle brackets in associated item path")
+            .span_suggestion(
+                // this is a best-effort recovery
+                path.span,
+                "try",
+                format!("<{}>::{}", ty_str, path),
+                Applicability::MaybeIncorrect,
+            )
+            .emit();
+
+        let path_span = ty_span.shrink_to_hi(); // use an empty path since `position` == 0
+        Ok(P(T::recovered(
+            Some(QSelf {
+                ty,
+                path_span,
+                position: 0,
+            }),
+            path,
+        )))
+    }
+
+    crate fn maybe_consume_incorrect_semicolon(&mut self, items: &[P<Item>]) -> bool {
+        if self.eat(&token::Semi) {
+            let mut err = self.struct_span_err(self.prev_span, "expected item, found `;`");
+            err.span_suggestion_short(
+                self.prev_span,
+                "remove this semicolon",
+                String::new(),
+                Applicability::MachineApplicable,
+            );
+            if !items.is_empty() {
+                let previous_item = &items[items.len() - 1];
+                let previous_item_kind_name = match previous_item.node {
+                    // say "braced struct" because tuple-structs and
+                    // braceless-empty-struct declarations do take a semicolon
+                    ItemKind::Struct(..) => Some("braced struct"),
+                    ItemKind::Enum(..) => Some("enum"),
+                    ItemKind::Trait(..) => Some("trait"),
+                    ItemKind::Union(..) => Some("union"),
+                    _ => None,
+                };
+                if let Some(name) = previous_item_kind_name {
+                    err.help(&format!(
+                        "{} declarations are not followed by a semicolon",
+                        name
+                    ));
+                }
+            }
+            err.emit();
+            true
+        } else {
+            false
+        }
+    }
+}
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index 1abc7832ffa..85a74df2357 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -30,6 +30,7 @@ pub mod parser;
 pub mod lexer;
 pub mod token;
 pub mod attr;
+pub mod diagnostics;
 
 pub mod classify;
 
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 8efe84cdf01..f70acb3e7da 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -189,41 +189,6 @@ enum PrevTokenKind {
     Other,
 }
 
-trait RecoverQPath: Sized + 'static {
-    const PATH_STYLE: PathStyle = PathStyle::Expr;
-    fn to_ty(&self) -> Option<P<Ty>>;
-    fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self;
-}
-
-impl RecoverQPath for Ty {
-    const PATH_STYLE: PathStyle = PathStyle::Type;
-    fn to_ty(&self) -> Option<P<Ty>> {
-        Some(P(self.clone()))
-    }
-    fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
-        Self { span: path.span, node: TyKind::Path(qself, path), id: ast::DUMMY_NODE_ID }
-    }
-}
-
-impl RecoverQPath for Pat {
-    fn to_ty(&self) -> Option<P<Ty>> {
-        self.to_ty()
-    }
-    fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
-        Self { span: path.span, node: PatKind::Path(qself, path), id: ast::DUMMY_NODE_ID }
-    }
-}
-
-impl RecoverQPath for Expr {
-    fn to_ty(&self) -> Option<P<Ty>> {
-        self.to_ty()
-    }
-    fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
-        Self { span: path.span, node: ExprKind::Path(qself, path),
-               attrs: ThinVec::new(), id: ast::DUMMY_NODE_ID }
-    }
-}
-
 /* ident is handled by common.rs */
 
 #[derive(Clone)]
@@ -1479,7 +1444,7 @@ impl<'a> Parser<'a> {
     fn span_err<S: Into<MultiSpan>>(&self, sp: S, m: &str) {
         self.sess.span_diagnostic.span_err(sp, m)
     }
-    fn struct_span_err<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> {
+    crate fn struct_span_err<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> {
         self.sess.span_diagnostic.struct_span_err(sp, m)
     }
     fn struct_span_warn<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> {
@@ -1882,99 +1847,6 @@ impl<'a> Parser<'a> {
         Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None))
     }
 
-    fn maybe_report_ambiguous_plus(&mut self, allow_plus: bool, impl_dyn_multi: bool, ty: &Ty) {
-        if !allow_plus && impl_dyn_multi {
-            let sum_with_parens = format!("({})", pprust::ty_to_string(&ty));
-            self.struct_span_err(ty.span, "ambiguous `+` in a type")
-                .span_suggestion(
-                    ty.span,
-                    "use parentheses to disambiguate",
-                    sum_with_parens,
-                    Applicability::MachineApplicable
-                ).emit();
-        }
-    }
-
-    fn maybe_recover_from_bad_type_plus(&mut self, allow_plus: bool, ty: &Ty) -> PResult<'a, ()> {
-        // Do not add `+` to expected tokens.
-        if !allow_plus || !self.token.is_like_plus() {
-            return Ok(())
-        }
-
-        self.bump(); // `+`
-        let bounds = self.parse_generic_bounds(None)?;
-        let sum_span = ty.span.to(self.prev_span);
-
-        let mut err = struct_span_err!(self.sess.span_diagnostic, sum_span, E0178,
-            "expected a path on the left-hand side of `+`, not `{}`", pprust::ty_to_string(ty));
-
-        match ty.node {
-            TyKind::Rptr(ref lifetime, ref mut_ty) => {
-                let sum_with_parens = pprust::to_string(|s| {
-                    use crate::print::pprust::PrintState;
-
-                    s.s.word("&")?;
-                    s.print_opt_lifetime(lifetime)?;
-                    s.print_mutability(mut_ty.mutbl)?;
-                    s.popen()?;
-                    s.print_type(&mut_ty.ty)?;
-                    s.print_type_bounds(" +", &bounds)?;
-                    s.pclose()
-                });
-                err.span_suggestion(
-                    sum_span,
-                    "try adding parentheses",
-                    sum_with_parens,
-                    Applicability::MachineApplicable
-                );
-            }
-            TyKind::Ptr(..) | TyKind::BareFn(..) => {
-                err.span_label(sum_span, "perhaps you forgot parentheses?");
-            }
-            _ => {
-                err.span_label(sum_span, "expected a path");
-            },
-        }
-        err.emit();
-        Ok(())
-    }
-
-    /// Try to recover from associated item paths like `[T]::AssocItem`/`(T, U)::AssocItem`.
-    /// Attempt to convert the base expression/pattern/type into a type, parse the `::AssocItem`
-    /// tail, and combine them into a `<Ty>::AssocItem` expression/pattern/type.
-    fn maybe_recover_from_bad_qpath<T: RecoverQPath>(&mut self, base: P<T>, allow_recovery: bool)
-                                                     -> PResult<'a, P<T>> {
-        // Do not add `::` to expected tokens.
-        if allow_recovery && self.token == token::ModSep {
-            if let Some(ty) = base.to_ty() {
-                return self.maybe_recover_from_bad_qpath_stage_2(ty.span, ty);
-            }
-        }
-        Ok(base)
-    }
-
-    /// Given an already parsed `Ty` parse the `::AssocItem` tail and
-    /// combine them into a `<Ty>::AssocItem` expression/pattern/type.
-    fn maybe_recover_from_bad_qpath_stage_2<T: RecoverQPath>(&mut self, ty_span: Span, ty: P<Ty>)
-                                                             -> PResult<'a, P<T>> {
-        self.expect(&token::ModSep)?;
-
-        let mut path = ast::Path { segments: Vec::new(), span: syntax_pos::DUMMY_SP };
-        self.parse_path_segments(&mut path.segments, T::PATH_STYLE)?;
-        path.span = ty_span.to(self.prev_span);
-
-        let ty_str = self.sess.source_map().span_to_snippet(ty_span)
-            .unwrap_or_else(|_| pprust::ty_to_string(&ty));
-        self.diagnostic()
-            .struct_span_err(path.span, "missing angle brackets in associated item path")
-            .span_suggestion( // this is a best-effort recovery
-                path.span, "try", format!("<{}>::{}", ty_str, path), Applicability::MaybeIncorrect
-            ).emit();
-
-        let path_span = ty_span.shrink_to_hi(); // use an empty path since `position` == 0
-        Ok(P(T::recovered(Some(QSelf { ty, path_span, position: 0 }), path)))
-    }
-
     fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> {
         let opt_lifetime = if self.check_lifetime() { Some(self.expect_lifetime()) } else { None };
         let mutbl = self.parse_mutability();
@@ -2410,7 +2282,7 @@ impl<'a> Parser<'a> {
         self.parse_path(style)
     }
 
-    fn parse_path_segments(&mut self,
+    crate fn parse_path_segments(&mut self,
                            segments: &mut Vec<PathSegment>,
                            style: PathStyle)
                            -> PResult<'a, ()> {
@@ -5815,7 +5687,8 @@ impl<'a> Parser<'a> {
         return Ok(bounds);
     }
 
-    fn parse_generic_bounds(&mut self, colon_span: Option<Span>) -> PResult<'a, GenericBounds> {
+    crate fn parse_generic_bounds(&mut self,
+                                  colon_span: Option<Span>) -> PResult<'a, GenericBounds> {
         self.parse_generic_bounds_common(true, colon_span)
     }
 
@@ -7352,37 +7225,6 @@ impl<'a> Parser<'a> {
         }
     }
 
-    fn maybe_consume_incorrect_semicolon(&mut self, items: &[P<Item>]) -> bool {
-        if self.eat(&token::Semi) {
-            let mut err = self.struct_span_err(self.prev_span, "expected item, found `;`");
-            err.span_suggestion_short(
-                self.prev_span,
-                "remove this semicolon",
-                String::new(),
-                Applicability::MachineApplicable,
-            );
-            if !items.is_empty() {
-                let previous_item = &items[items.len()-1];
-                let previous_item_kind_name = match previous_item.node {
-                    // say "braced struct" because tuple-structs and
-                    // braceless-empty-struct declarations do take a semicolon
-                    ItemKind::Struct(..) => Some("braced struct"),
-                    ItemKind::Enum(..) => Some("enum"),
-                    ItemKind::Trait(..) => Some("trait"),
-                    ItemKind::Union(..) => Some("union"),
-                    _ => None,
-                };
-                if let Some(name) = previous_item_kind_name {
-                    err.help(&format!("{} declarations are not followed by a semicolon", name));
-                }
-            }
-            err.emit();
-            true
-        } else {
-            false
-        }
-    }
-
     /// Given a termination token, parses all of the items in a module.
     fn parse_mod_items(&mut self, term: &token::Token, inner_lo: Span) -> PResult<'a, Mod> {
         let mut items = vec![];
@@ -8878,13 +8720,39 @@ impl<'a> Parser<'a> {
 
                 // Construct a name for our temporary argument.
                 let name = format!("__arg{}", index);
-                let ident = Ident::from_str(&name);
+                let ident = Ident::from_str(&name).gensym();
+
+                // Check if this is a ident pattern, if so, we can optimize and avoid adding a
+                // `let <pat> = __argN;` statement, instead just adding a `let <pat> = <pat>;`
+                // statement.
+                let (ident, is_simple_pattern) = match input.pat.node {
+                    PatKind::Ident(_, ident, _) => (ident, true),
+                    _ => (ident, false),
+                };
 
                 // Construct an argument representing `__argN: <ty>` to replace the argument of the
-                // async function.
-                let arg = Arg {
-                    ty: input.ty.clone(),
-                    id,
+                // async function if it isn't a simple pattern.
+                let arg = if is_simple_pattern {
+                    None
+                } else {
+                    Some(Arg {
+                        ty: input.ty.clone(),
+                        id,
+                        pat: P(Pat {
+                            id,
+                            node: PatKind::Ident(
+                                BindingMode::ByValue(Mutability::Immutable), ident, None,
+                            ),
+                            span,
+                        }),
+                        source: ArgSource::AsyncFn(input.pat.clone()),
+                    })
+                };
+
+                // Construct a `let __argN = __argN;` statement to insert at the top of the
+                // async closure. This makes sure that the argument is captured by the closure and
+                // that the drop order is correct.
+                let move_local = Local {
                     pat: P(Pat {
                         id,
                         node: PatKind::Ident(
@@ -8892,13 +8760,6 @@ impl<'a> Parser<'a> {
                         ),
                         span,
                     }),
-                    source: ArgSource::AsyncFn(input.pat.clone()),
-                };
-
-                // Construct a `let <pat> = __argN;` statement to insert at the top of the
-                // async closure.
-                let local = P(Local {
-                    pat: input.pat.clone(),
                     // We explicitly do not specify the type for this statement. When the user's
                     // argument type is `impl Trait` then this would require the
                     // `impl_trait_in_bindings` feature to also be present for that same type to
@@ -8918,10 +8779,25 @@ impl<'a> Parser<'a> {
                     span,
                     attrs: ThinVec::new(),
                     source: LocalSource::AsyncFn,
-                });
-                let stmt = Stmt { id, node: StmtKind::Local(local), span, };
+                };
+
+                // Construct a `let <pat> = __argN;` statement to insert at the top of the
+                // async closure if this isn't a simple pattern.
+                let pat_stmt = if is_simple_pattern {
+                    None
+                } else {
+                    Some(Stmt {
+                        id,
+                        node: StmtKind::Local(P(Local {
+                            pat: input.pat.clone(),
+                            ..move_local.clone()
+                        })),
+                        span,
+                    })
+                };
 
-                arguments.push(AsyncArgument { ident, arg, stmt });
+                let move_stmt = Stmt { id, node: StmtKind::Local(P(move_local)), span };
+                arguments.push(AsyncArgument { ident, arg, pat_stmt, move_stmt });
             }
         }
     }
diff --git a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs
index 5330470da16..4e43aa96e1d 100644
--- a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs
+++ b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs
@@ -15,7 +15,7 @@ use rustc::session::Session;
 use rustc::session::config::OutputFilenames;
 use rustc::ty::TyCtxt;
 use rustc::ty::query::Providers;
-use rustc::middle::cstore::MetadataLoader;
+use rustc::middle::cstore::{EncodedMetadata, MetadataLoader};
 use rustc::dep_graph::DepGraph;
 use rustc::util::common::ErrorReported;
 use rustc_codegen_utils::codegen_backend::CodegenBackend;
@@ -61,6 +61,8 @@ impl CodegenBackend for TheBackend {
     fn codegen_crate<'a, 'tcx>(
         &self,
         tcx: TyCtxt<'a, 'tcx, 'tcx>,
+        _metadata: EncodedMetadata,
+        _need_metadata_module: bool,
         _rx: mpsc::Receiver<Box<Any + Send>>
     ) -> Box<Any> {
         use rustc::hir::def_id::LOCAL_CRATE;
diff --git a/src/test/run-pass/issue-54716.rs b/src/test/run-pass/issue-54716.rs
deleted file mode 100644
index 961c412f5ec..00000000000
--- a/src/test/run-pass/issue-54716.rs
+++ /dev/null
@@ -1,184 +0,0 @@
-// aux-build:arc_wake.rs
-// edition:2018
-// run-pass
-
-#![allow(unused_variables)]
-#![feature(async_await, await_macro)]
-
-extern crate arc_wake;
-
-use arc_wake::ArcWake;
-use std::cell::RefCell;
-use std::future::Future;
-use std::marker::PhantomData;
-use std::sync::Arc;
-use std::rc::Rc;
-use std::task::Context;
-
-struct EmptyWaker;
-
-impl ArcWake for EmptyWaker {
-    fn wake(self: Arc<Self>) {}
-}
-
-#[derive(Debug, Eq, PartialEq)]
-enum DropOrder {
-    Function,
-    Val(&'static str),
-}
-
-type DropOrderListPtr = Rc<RefCell<Vec<DropOrder>>>;
-
-struct D(&'static str, DropOrderListPtr);
-
-impl Drop for D {
-    fn drop(&mut self) {
-        self.1.borrow_mut().push(DropOrder::Val(self.0));
-    }
-}
-
-/// Check that unused bindings are dropped after the function is polled.
-async fn foo(x: D, _y: D) {
-    x.1.borrow_mut().push(DropOrder::Function);
-}
-
-/// Check that underscore patterns are dropped after the function is polled.
-async fn bar(x: D, _: D) {
-    x.1.borrow_mut().push(DropOrder::Function);
-}
-
-/// Check that underscore patterns within more complex patterns are dropped after the function
-/// is polled.
-async fn baz((x, _): (D, D)) {
-    x.1.borrow_mut().push(DropOrder::Function);
-}
-
-/// Check that underscore and unused bindings within and outwith more complex patterns are dropped
-/// after the function is polled.
-async fn foobar(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
-    x.1.borrow_mut().push(DropOrder::Function);
-}
-
-struct Foo;
-
-impl Foo {
-    /// Check that unused bindings are dropped after the method is polled.
-    async fn foo(x: D, _y: D) {
-        x.1.borrow_mut().push(DropOrder::Function);
-    }
-
-    /// Check that underscore patterns are dropped after the method is polled.
-    async fn bar(x: D, _: D) {
-        x.1.borrow_mut().push(DropOrder::Function);
-    }
-
-    /// Check that underscore patterns within more complex patterns are dropped after the method
-    /// is polled.
-    async fn baz((x, _): (D, D)) {
-        x.1.borrow_mut().push(DropOrder::Function);
-    }
-
-    /// Check that underscore and unused bindings within and outwith more complex patterns are
-    /// dropped after the method is polled.
-    async fn foobar(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
-        x.1.borrow_mut().push(DropOrder::Function);
-    }
-}
-
-struct Bar<'a>(PhantomData<&'a ()>);
-
-impl<'a> Bar<'a> {
-    /// Check that unused bindings are dropped after the method with self is polled.
-    async fn foo(&'a self, x: D, _y: D) {
-        x.1.borrow_mut().push(DropOrder::Function);
-    }
-
-    /// Check that underscore patterns are dropped after the method with self is polled.
-    async fn bar(&'a self, x: D, _: D) {
-        x.1.borrow_mut().push(DropOrder::Function);
-    }
-
-    /// Check that underscore patterns within more complex patterns are dropped after the method
-    /// with self is polled.
-    async fn baz(&'a self, (x, _): (D, D)) {
-        x.1.borrow_mut().push(DropOrder::Function);
-    }
-
-    /// Check that underscore and unused bindings within and outwith more complex patterns are
-    /// dropped after the method with self is polled.
-    async fn foobar(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
-        x.1.borrow_mut().push(DropOrder::Function);
-    }
-}
-
-fn assert_drop_order_after_poll<Fut: Future<Output = ()>>(
-    f: impl FnOnce(DropOrderListPtr) -> Fut,
-    expected_order: &[DropOrder],
-) {
-    let empty = Arc::new(EmptyWaker);
-    let waker = ArcWake::into_waker(empty);
-    let mut cx = Context::from_waker(&waker);
-
-    let actual_order = Rc::new(RefCell::new(Vec::new()));
-    let mut fut = Box::pin(f(actual_order.clone()));
-    let _ = fut.as_mut().poll(&mut cx);
-
-    assert_eq!(*actual_order.borrow(), expected_order);
-}
-
-fn main() {
-    use DropOrder::*;
-
-    // At time of writing (23/04/19), the `bar` and `foobar` tests do not output the same order as
-    // the equivalent non-async functions. This is because the drop order of captured variables
-    // doesn't match the drop order of arguments in a function.
-
-    // Free functions (see doc comment on function for what it tests).
-    assert_drop_order_after_poll(|l| foo(D("x", l.clone()), D("_y", l.clone())),
-                                 &[Function, Val("_y"), Val("x")]);
-    assert_drop_order_after_poll(|l| bar(D("x", l.clone()), D("_", l.clone())),
-                                 &[Function, Val("x"), Val("_")]);
-    assert_drop_order_after_poll(|l| baz((D("x", l.clone()), D("_", l.clone()))),
-                                 &[Function, Val("x"), Val("_")]);
-    assert_drop_order_after_poll(|l| {
-        foobar(
-            D("x", l.clone()),
-            (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
-            D("_", l.clone()),
-            D("_y", l.clone()),
-        )
-    }, &[Function, Val("_y"), Val("_c"), Val("a"), Val("x"), Val("_"), Val("_")]);
-
-    // Methods w/out self (see doc comment on function for what it tests).
-    assert_drop_order_after_poll(|l| Foo::foo(D("x", l.clone()), D("_y", l.clone())),
-                                 &[Function, Val("_y"), Val("x")]);
-    assert_drop_order_after_poll(|l| Foo::bar(D("x", l.clone()), D("_", l.clone())),
-                                 &[Function, Val("x"), Val("_")]);
-    assert_drop_order_after_poll(|l| Foo::baz((D("x", l.clone()), D("_", l.clone()))),
-                                 &[Function, Val("x"), Val("_")]);
-    assert_drop_order_after_poll(|l| {
-        Foo::foobar(
-            D("x", l.clone()),
-            (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
-            D("_", l.clone()),
-            D("_y", l.clone()),
-        )
-    }, &[Function, Val("_y"), Val("_c"), Val("a"), Val("x"), Val("_"), Val("_")]);
-
-    // Methods (see doc comment on function for what it tests).
-    let b = Bar(Default::default());
-    assert_drop_order_after_poll(|l| b.foo(D("x", l.clone()), D("_y", l.clone())),
-                                 &[Function, Val("_y"), Val("x")]);
-    assert_drop_order_after_poll(|l| b.bar(D("x", l.clone()), D("_", l.clone())),
-                                 &[Function, Val("x"), Val("_")]);
-    assert_drop_order_after_poll(|l| b.baz((D("x", l.clone()), D("_", l.clone()))),
-                                 &[Function, Val("x"), Val("_")]);
-    assert_drop_order_after_poll(|l| {
-        b.foobar(
-            D("x", l.clone()),
-            (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
-            D("_", l.clone()),
-            D("_y", l.clone()),
-        )
-    }, &[Function, Val("_y"), Val("_c"), Val("a"), Val("x"), Val("_"), Val("_")]);
-}
diff --git a/src/test/ui/async-await/auxiliary/arc_wake.rs b/src/test/ui/async-await/auxiliary/arc_wake.rs
new file mode 100644
index 00000000000..c21886f26f4
--- /dev/null
+++ b/src/test/ui/async-await/auxiliary/arc_wake.rs
@@ -0,0 +1,64 @@
+// edition:2018
+
+use std::sync::Arc;
+use std::task::{
+    Waker, RawWaker, RawWakerVTable,
+};
+
+macro_rules! waker_vtable {
+    ($ty:ident) => {
+        &RawWakerVTable::new(
+            clone_arc_raw::<$ty>,
+            wake_arc_raw::<$ty>,
+            wake_by_ref_arc_raw::<$ty>,
+            drop_arc_raw::<$ty>,
+        )
+    };
+}
+
+pub trait ArcWake {
+    fn wake(self: Arc<Self>);
+
+    fn wake_by_ref(arc_self: &Arc<Self>) {
+        arc_self.clone().wake()
+    }
+
+    fn into_waker(wake: Arc<Self>) -> Waker where Self: Sized
+    {
+        let ptr = Arc::into_raw(wake) as *const ();
+
+        unsafe {
+            Waker::from_raw(RawWaker::new(ptr, waker_vtable!(Self)))
+        }
+    }
+}
+
+unsafe fn increase_refcount<T: ArcWake>(data: *const ()) {
+    // Retain Arc by creating a copy
+    let arc: Arc<T> = Arc::from_raw(data as *const T);
+    let arc_clone = arc.clone();
+    // Forget the Arcs again, so that the refcount isn't decrased
+    let _ = Arc::into_raw(arc);
+    let _ = Arc::into_raw(arc_clone);
+}
+
+unsafe fn clone_arc_raw<T: ArcWake>(data: *const ()) -> RawWaker {
+    increase_refcount::<T>(data);
+    RawWaker::new(data, waker_vtable!(T))
+}
+
+unsafe fn drop_arc_raw<T: ArcWake>(data: *const ()) {
+    // Drop Arc
+    let _: Arc<T> = Arc::from_raw(data as *const T);
+}
+
+unsafe fn wake_arc_raw<T: ArcWake>(data: *const ()) {
+    let arc: Arc<T> = Arc::from_raw(data as *const T);
+    ArcWake::wake(arc);
+}
+
+unsafe fn wake_by_ref_arc_raw<T: ArcWake>(data: *const ()) {
+    let arc: Arc<T> = Arc::from_raw(data as *const T);
+    ArcWake::wake_by_ref(&arc);
+    let _ = Arc::into_raw(arc);
+}
diff --git a/src/test/ui/async-await/drop-order-for-async-fn-parameters.rs b/src/test/ui/async-await/drop-order-for-async-fn-parameters.rs
new file mode 100644
index 00000000000..708c5704984
--- /dev/null
+++ b/src/test/ui/async-await/drop-order-for-async-fn-parameters.rs
@@ -0,0 +1,263 @@
+// aux-build:arc_wake.rs
+// edition:2018
+// run-pass
+
+#![allow(unused_variables)]
+#![feature(async_await, await_macro)]
+
+// Test that the drop order for parameters in a fn and async fn matches up. Also test that
+// parameters (used or unused) are not dropped until the async fn completes execution.
+// See also #54716.
+
+extern crate arc_wake;
+
+use arc_wake::ArcWake;
+use std::cell::RefCell;
+use std::future::Future;
+use std::marker::PhantomData;
+use std::sync::Arc;
+use std::rc::Rc;
+use std::task::Context;
+
+struct EmptyWaker;
+
+impl ArcWake for EmptyWaker {
+    fn wake(self: Arc<Self>) {}
+}
+
+#[derive(Debug, Eq, PartialEq)]
+enum DropOrder {
+    Function,
+    Val(&'static str),
+}
+
+type DropOrderListPtr = Rc<RefCell<Vec<DropOrder>>>;
+
+struct D(&'static str, DropOrderListPtr);
+
+impl Drop for D {
+    fn drop(&mut self) {
+        self.1.borrow_mut().push(DropOrder::Val(self.0));
+    }
+}
+
+/// Check that unused bindings are dropped after the function is polled.
+async fn foo_async(x: D, _y: D) {
+    x.1.borrow_mut().push(DropOrder::Function);
+}
+
+fn foo_sync(x: D, _y: D) {
+    x.1.borrow_mut().push(DropOrder::Function);
+}
+
+/// Check that underscore patterns are dropped after the function is polled.
+async fn bar_async(x: D, _: D) {
+    x.1.borrow_mut().push(DropOrder::Function);
+}
+
+fn bar_sync(x: D, _: D) {
+    x.1.borrow_mut().push(DropOrder::Function);
+}
+
+/// Check that underscore patterns within more complex patterns are dropped after the function
+/// is polled.
+async fn baz_async((x, _): (D, D)) {
+    x.1.borrow_mut().push(DropOrder::Function);
+}
+
+fn baz_sync((x, _): (D, D)) {
+    x.1.borrow_mut().push(DropOrder::Function);
+}
+
+/// Check that underscore and unused bindings within and outwith more complex patterns are dropped
+/// after the function is polled.
+async fn foobar_async(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
+    x.1.borrow_mut().push(DropOrder::Function);
+}
+
+fn foobar_sync(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
+    x.1.borrow_mut().push(DropOrder::Function);
+}
+
+struct Foo;
+
+impl Foo {
+    /// Check that unused bindings are dropped after the method is polled.
+    async fn foo_async(x: D, _y: D) {
+        x.1.borrow_mut().push(DropOrder::Function);
+    }
+
+    fn foo_sync(x: D, _y: D) {
+        x.1.borrow_mut().push(DropOrder::Function);
+    }
+
+    /// Check that underscore patterns are dropped after the method is polled.
+    async fn bar_async(x: D, _: D) {
+        x.1.borrow_mut().push(DropOrder::Function);
+    }
+
+    fn bar_sync(x: D, _: D) {
+        x.1.borrow_mut().push(DropOrder::Function);
+    }
+
+    /// Check that underscore patterns within more complex patterns are dropped after the method
+    /// is polled.
+    async fn baz_async((x, _): (D, D)) {
+        x.1.borrow_mut().push(DropOrder::Function);
+    }
+
+    fn baz_sync((x, _): (D, D)) {
+        x.1.borrow_mut().push(DropOrder::Function);
+    }
+
+    /// Check that underscore and unused bindings within and outwith more complex patterns are
+    /// dropped after the method is polled.
+    async fn foobar_async(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
+        x.1.borrow_mut().push(DropOrder::Function);
+    }
+
+    fn foobar_sync(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
+        x.1.borrow_mut().push(DropOrder::Function);
+    }
+}
+
+struct Bar<'a>(PhantomData<&'a ()>);
+
+impl<'a> Bar<'a> {
+    /// Check that unused bindings are dropped after the method with self is polled.
+    async fn foo_async(&'a self, x: D, _y: D) {
+        x.1.borrow_mut().push(DropOrder::Function);
+    }
+
+    fn foo_sync(&'a self, x: D, _y: D) {
+        x.1.borrow_mut().push(DropOrder::Function);
+    }
+
+    /// Check that underscore patterns are dropped after the method with self is polled.
+    async fn bar_async(&'a self, x: D, _: D) {
+        x.1.borrow_mut().push(DropOrder::Function);
+    }
+
+    fn bar_sync(&'a self, x: D, _: D) {
+        x.1.borrow_mut().push(DropOrder::Function);
+    }
+
+    /// Check that underscore patterns within more complex patterns are dropped after the method
+    /// with self is polled.
+    async fn baz_async(&'a self, (x, _): (D, D)) {
+        x.1.borrow_mut().push(DropOrder::Function);
+    }
+
+    fn baz_sync(&'a self, (x, _): (D, D)) {
+        x.1.borrow_mut().push(DropOrder::Function);
+    }
+
+    /// Check that underscore and unused bindings within and outwith more complex patterns are
+    /// dropped after the method with self is polled.
+    async fn foobar_async(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
+        x.1.borrow_mut().push(DropOrder::Function);
+    }
+
+    fn foobar_sync(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
+        x.1.borrow_mut().push(DropOrder::Function);
+    }
+}
+
+fn assert_drop_order_after_poll<Fut: Future<Output = ()>>(
+    f: impl FnOnce(DropOrderListPtr) -> Fut,
+    g: impl FnOnce(DropOrderListPtr),
+) {
+    let empty = Arc::new(EmptyWaker);
+    let waker = ArcWake::into_waker(empty);
+    let mut cx = Context::from_waker(&waker);
+
+    let actual_order = Rc::new(RefCell::new(Vec::new()));
+    let mut fut = Box::pin(f(actual_order.clone()));
+    let _ = fut.as_mut().poll(&mut cx);
+
+    let expected_order = Rc::new(RefCell::new(Vec::new()));
+    g(expected_order.clone());
+
+    assert_eq!(*actual_order.borrow(), *expected_order.borrow());
+}
+
+fn main() {
+    // Free functions (see doc comment on function for what it tests).
+    assert_drop_order_after_poll(|l| foo_async(D("x", l.clone()), D("_y", l.clone())),
+                                 |l| foo_sync(D("x", l.clone()), D("_y", l.clone())));
+    assert_drop_order_after_poll(|l| bar_async(D("x", l.clone()), D("_", l.clone())),
+                                 |l| bar_sync(D("x", l.clone()), D("_", l.clone())));
+    assert_drop_order_after_poll(|l| baz_async((D("x", l.clone()), D("_", l.clone()))),
+                                 |l| baz_sync((D("x", l.clone()), D("_", l.clone()))));
+    assert_drop_order_after_poll(
+        |l| {
+            foobar_async(
+                D("x", l.clone()),
+                (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+                D("_", l.clone()),
+                D("_y", l.clone()),
+            )
+        },
+        |l| {
+            foobar_sync(
+                D("x", l.clone()),
+                (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+                D("_", l.clone()),
+                D("_y", l.clone()),
+            )
+        },
+    );
+
+    // Methods w/out self (see doc comment on function for what it tests).
+    assert_drop_order_after_poll(|l| Foo::foo_async(D("x", l.clone()), D("_y", l.clone())),
+                                 |l| Foo::foo_sync(D("x", l.clone()), D("_y", l.clone())));
+    assert_drop_order_after_poll(|l| Foo::bar_async(D("x", l.clone()), D("_", l.clone())),
+                                 |l| Foo::bar_sync(D("x", l.clone()), D("_", l.clone())));
+    assert_drop_order_after_poll(|l| Foo::baz_async((D("x", l.clone()), D("_", l.clone()))),
+                                 |l| Foo::baz_sync((D("x", l.clone()), D("_", l.clone()))));
+    assert_drop_order_after_poll(
+        |l| {
+            Foo::foobar_async(
+                D("x", l.clone()),
+                (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+                D("_", l.clone()),
+                D("_y", l.clone()),
+            )
+        },
+        |l| {
+            Foo::foobar_sync(
+                D("x", l.clone()),
+                (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+                D("_", l.clone()),
+                D("_y", l.clone()),
+            )
+        },
+    );
+
+    // Methods (see doc comment on function for what it tests).
+    let b = Bar(Default::default());
+    assert_drop_order_after_poll(|l| b.foo_async(D("x", l.clone()), D("_y", l.clone())),
+                                 |l| b.foo_sync(D("x", l.clone()), D("_y", l.clone())));
+    assert_drop_order_after_poll(|l| b.bar_async(D("x", l.clone()), D("_", l.clone())),
+                                 |l| b.bar_sync(D("x", l.clone()), D("_", l.clone())));
+    assert_drop_order_after_poll(|l| b.baz_async((D("x", l.clone()), D("_", l.clone()))),
+                                 |l| b.baz_sync((D("x", l.clone()), D("_", l.clone()))));
+    assert_drop_order_after_poll(
+        |l| {
+            b.foobar_async(
+                D("x", l.clone()),
+                (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+                D("_", l.clone()),
+                D("_y", l.clone()),
+            )
+        },
+        |l| {
+            b.foobar_sync(
+                D("x", l.clone()),
+                (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+                D("_", l.clone()),
+                D("_y", l.clone()),
+            )
+        },
+    );
+}
diff --git a/src/test/ui/async-await/drop-order-locals-are-hidden.rs b/src/test/ui/async-await/drop-order-locals-are-hidden.rs
new file mode 100644
index 00000000000..10dc5e27f6f
--- /dev/null
+++ b/src/test/ui/async-await/drop-order-locals-are-hidden.rs
@@ -0,0 +1,11 @@
+// edition:2018
+
+#![allow(unused_variables)]
+#![feature(async_await)]
+
+async fn foobar_async(x: u32, (a, _, _c): (u32, u32, u32), _: u32, _y: u32) {
+    assert_eq!(__arg1, (1, 2, 3)); //~ ERROR cannot find value `__arg1` in this scope [E0425]
+    assert_eq!(__arg2, 4); //~ ERROR cannot find value `__arg2` in this scope [E0425]
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/drop-order-locals-are-hidden.stderr b/src/test/ui/async-await/drop-order-locals-are-hidden.stderr
new file mode 100644
index 00000000000..ca0da6b7c96
--- /dev/null
+++ b/src/test/ui/async-await/drop-order-locals-are-hidden.stderr
@@ -0,0 +1,15 @@
+error[E0425]: cannot find value `__arg1` in this scope
+  --> $DIR/drop-order-locals-are-hidden.rs:7:16
+   |
+LL |     assert_eq!(__arg1, (1, 2, 3));
+   |                ^^^^^^ not found in this scope
+
+error[E0425]: cannot find value `__arg2` in this scope
+  --> $DIR/drop-order-locals-are-hidden.rs:8:16
+   |
+LL |     assert_eq!(__arg2, 4);
+   |                ^^^^^^ not found in this scope
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/pub/pub-restricted.stderr b/src/test/ui/pub/pub-restricted.stderr
index 044e5fc5188..7eeefa95505 100644
--- a/src/test/ui/pub/pub-restricted.stderr
+++ b/src/test/ui/pub/pub-restricted.stderr
@@ -50,3 +50,4 @@ LL |         pub (in x) non_parent_invalid: usize,
 
 error: aborting due to 5 previous errors
 
+For more information about this error, try `rustc --explain E0704`.