From 9b00e219fef1d315829d0e21b24c20ec7e9630ab Mon Sep 17 00:00:00 2001
From: Mark Rousskov <mark.simulacrum@gmail.com>
Date: Wed, 25 Sep 2019 21:02:50 -0400
Subject: [PATCH 01/24] Remove unused DepTrackingMap

---
 src/librustc/dep_graph/dep_tracking_map.rs | 87 ----------------------
 src/librustc/dep_graph/mod.rs              |  2 -
 src/librustc/traits/codegen/mod.rs         | 29 +-------
 src/librustc/util/common.rs                | 41 +---------
 4 files changed, 3 insertions(+), 156 deletions(-)
 delete mode 100644 src/librustc/dep_graph/dep_tracking_map.rs

diff --git a/src/librustc/dep_graph/dep_tracking_map.rs b/src/librustc/dep_graph/dep_tracking_map.rs
deleted file mode 100644
index ee22d0b755a09..0000000000000
--- a/src/librustc/dep_graph/dep_tracking_map.rs
+++ /dev/null
@@ -1,87 +0,0 @@
-use rustc_data_structures::fx::FxHashMap;
-use std::cell::RefCell;
-use std::hash::Hash;
-use std::marker::PhantomData;
-use crate::util::common::MemoizationMap;
-
-use super::{DepKind, DepNodeIndex, DepGraph};
-
-/// A DepTrackingMap offers a subset of the `Map` API and ensures that
-/// we make calls to `read` and `write` as appropriate. We key the
-/// maps with a unique type for brevity.
-pub struct DepTrackingMap<M: DepTrackingMapConfig> {
-    phantom: PhantomData<M>,
-    graph: DepGraph,
-    map: FxHashMap<M::Key, (M::Value, DepNodeIndex)>,
-}
-
-pub trait DepTrackingMapConfig {
-    type Key: Eq + Hash + Clone;
-    type Value: Clone;
-    fn to_dep_kind() -> DepKind;
-}
-
-impl<M: DepTrackingMapConfig> DepTrackingMap<M> {
-    pub fn new(graph: DepGraph) -> DepTrackingMap<M> {
-        DepTrackingMap {
-            phantom: PhantomData,
-            graph,
-            map: Default::default(),
-        }
-    }
-}
-
-impl<M: DepTrackingMapConfig> MemoizationMap for RefCell<DepTrackingMap<M>> {
-    type Key = M::Key;
-    type Value = M::Value;
-
-    /// Memoizes an entry in the dep-tracking-map. If the entry is not
-    /// already present, then `op` will be executed to compute its value.
-    /// The resulting dependency graph looks like this:
-    ///
-    ///     [op] -> Map(key) -> CurrentTask
-    ///
-    /// Here, `[op]` represents whatever nodes `op` reads in the
-    /// course of execution; `Map(key)` represents the node for this
-    /// map, and `CurrentTask` represents the current task when
-    /// `memoize` is invoked.
-    ///
-    /// **Important:** when `op` is invoked, the current task will be
-    /// switched to `Map(key)`. Therefore, if `op` makes use of any
-    /// HIR nodes or shared state accessed through its closure
-    /// environment, it must explicitly register a read of that
-    /// state. As an example, see `type_of_item` in `collect`,
-    /// which looks something like this:
-    ///
-    /// ```
-    /// fn type_of_item(..., item: &hir::Item) -> Ty<'tcx> {
-    ///     let item_def_id = ccx.tcx.hir().local_def_id(it.hir_id);
-    ///     ccx.tcx.item_types.memoized(item_def_id, || {
-    ///         ccx.tcx.dep_graph.read(DepNode::Hir(item_def_id)); // (*)
-    ///         compute_type_of_item(ccx, item)
-    ///     });
-    /// }
-    /// ```
-    ///
-    /// The key is the line marked `(*)`: the closure implicitly
-    /// accesses the body of the item `item`, so we register a read
-    /// from `Hir(item_def_id)`.
-    fn memoize<OP>(&self, key: M::Key, op: OP) -> M::Value
-        where OP: FnOnce() -> M::Value
-    {
-        let graph;
-        {
-            let this = self.borrow();
-            if let Some(&(ref result, dep_node)) = this.map.get(&key) {
-                this.graph.read_index(dep_node);
-                return result.clone();
-            }
-            graph = this.graph.clone();
-        }
-
-        let (result, dep_node) = graph.with_anon_task(M::to_dep_kind(), op);
-        self.borrow_mut().map.insert(key, (result.clone(), dep_node));
-        graph.read_index(dep_node);
-        result
-    }
-}
diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs
index 1535e6d349cf1..43f3d7e89cd5c 100644
--- a/src/librustc/dep_graph/mod.rs
+++ b/src/librustc/dep_graph/mod.rs
@@ -1,6 +1,5 @@
 pub mod debug;
 mod dep_node;
-mod dep_tracking_map;
 mod graph;
 mod prev;
 mod query;
@@ -8,7 +7,6 @@ mod safe;
 mod serialized;
 pub mod cgu_reuse_tracker;
 
-pub use self::dep_tracking_map::{DepTrackingMap, DepTrackingMapConfig};
 pub use self::dep_node::{DepNode, DepKind, DepConstructor, WorkProductId, RecoverKey, label_strs};
 pub use self::graph::{DepGraph, WorkProduct, DepNodeIndex, DepNodeColor, TaskDeps, hash_result};
 pub use self::graph::WorkProductFileKind;
diff --git a/src/librustc/traits/codegen/mod.rs b/src/librustc/traits/codegen/mod.rs
index 97fb430a3e051..9dff699deb8af 100644
--- a/src/librustc/traits/codegen/mod.rs
+++ b/src/librustc/traits/codegen/mod.rs
@@ -3,12 +3,10 @@
 // seems likely that they should eventually be merged into more
 // general routines.
 
-use crate::dep_graph::{DepKind, DepTrackingMapConfig};
-use std::marker::PhantomData;
 use crate::infer::InferCtxt;
 use crate::traits::{FulfillmentContext, Obligation, ObligationCause, SelectionContext,
              TraitEngine, Vtable};
-use crate::ty::{self, Ty, TyCtxt};
+use crate::ty::{self, TyCtxt};
 use crate::ty::subst::{Subst, SubstsRef};
 use crate::ty::fold::TypeFoldable;
 
@@ -100,33 +98,8 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 }
 
-// Implement DepTrackingMapConfig for `trait_cache`
-pub struct TraitSelectionCache<'tcx> {
-    data: PhantomData<&'tcx ()>
-}
-
-impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> {
-    type Key = (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>);
-    type Value = Vtable<'tcx, ()>;
-    fn to_dep_kind() -> DepKind {
-        DepKind::TraitSelect
-    }
-}
-
 // # Global Cache
 
-pub struct ProjectionCache<'tcx> {
-    data: PhantomData<&'tcx ()>,
-}
-
-impl<'tcx> DepTrackingMapConfig for ProjectionCache<'tcx> {
-    type Key = Ty<'tcx>;
-    type Value = Ty<'tcx>;
-    fn to_dep_kind() -> DepKind {
-        DepKind::TraitSelect
-    }
-}
-
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     /// Finishes processes any obligations that remain in the
     /// fulfillment context, and then returns the result with all type
diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs
index 2475b93d95f32..0f472126695e0 100644
--- a/src/librustc/util/common.rs
+++ b/src/librustc/util/common.rs
@@ -1,10 +1,9 @@
 #![allow(non_camel_case_types)]
 
-use rustc_data_structures::{fx::FxHashMap, sync::Lock};
+use rustc_data_structures::sync::Lock;
 
-use std::cell::{RefCell, Cell};
+use std::cell::Cell;
 use std::fmt::Debug;
-use std::hash::Hash;
 use std::time::{Duration, Instant};
 
 use std::sync::mpsc::{Sender};
@@ -279,39 +278,3 @@ pub fn indenter() -> Indenter {
     debug!(">>");
     Indenter { _cannot_construct_outside_of_this_module: () }
 }
-
-pub trait MemoizationMap {
-    type Key: Clone;
-    type Value: Clone;
-
-    /// If `key` is present in the map, return the value,
-    /// otherwise invoke `op` and store the value in the map.
-    ///
-    /// N.B., if the receiver is a `DepTrackingMap`, special care is
-    /// needed in the `op` to ensure that the correct edges are
-    /// added into the dep graph. See the `DepTrackingMap` impl for
-    /// more details!
-    fn memoize<OP>(&self, key: Self::Key, op: OP) -> Self::Value
-        where OP: FnOnce() -> Self::Value;
-}
-
-impl<K, V> MemoizationMap for RefCell<FxHashMap<K,V>>
-    where K: Hash+Eq+Clone, V: Clone
-{
-    type Key = K;
-    type Value = V;
-
-    fn memoize<OP>(&self, key: K, op: OP) -> V
-        where OP: FnOnce() -> V
-    {
-        let result = self.borrow().get(&key).cloned();
-        match result {
-            Some(result) => result,
-            None => {
-                let result = op();
-                self.borrow_mut().insert(key, result.clone());
-                result
-            }
-        }
-    }
-}

From dd38a0f6c72928b59ffc266f52954b6cfcc5f491 Mon Sep 17 00:00:00 2001
From: Baoshan Pang <baoshan.pang@windriver.com>
Date: Wed, 25 Sep 2019 20:10:29 -0700
Subject: [PATCH 02/24] update rtpSpawn's parameters type(It's prototype has
 been updated in libc)

---
 src/libstd/sys/vxworks/process/process_vxworks.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/libstd/sys/vxworks/process/process_vxworks.rs b/src/libstd/sys/vxworks/process/process_vxworks.rs
index beb20aa48169a..7446471ae3122 100644
--- a/src/libstd/sys/vxworks/process/process_vxworks.rs
+++ b/src/libstd/sys/vxworks/process/process_vxworks.rs
@@ -54,8 +54,8 @@ impl Command {
 
             let ret = libc::rtpSpawn(
                 self.get_argv()[0],                   // executing program
-                self.get_argv().as_ptr() as *const _, // argv
-                *sys::os::environ() as *const *const c_char,
+                self.get_argv().as_ptr() as *mut *const c_char, // argv
+                *sys::os::environ() as *mut *const c_char,
                 100 as c_int,                         // initial priority
                 thread::min_stack(),                  // initial stack size.
                 0,                                    // options

From 3e4f5826990b85b99e0d3cb9e47867e6ce6737e1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= <matti@marinelayer.io>
Date: Thu, 26 Sep 2019 13:19:14 +0200
Subject: [PATCH 03/24] Upgrade env_logger to 0.7

---
 Cargo.lock                       | 4 ++--
 src/librustc_driver/Cargo.toml   | 2 +-
 src/tools/compiletest/Cargo.toml | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index cbaf7d801ca06..df79a180aaae9 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -534,7 +534,7 @@ name = "compiletest"
 version = "0.0.0"
 dependencies = [
  "diff",
- "env_logger 0.6.2",
+ "env_logger 0.7.0",
  "getopts",
  "lazy_static 1.3.0",
  "libc",
@@ -3420,7 +3420,7 @@ dependencies = [
 name = "rustc_driver"
 version = "0.0.0"
 dependencies = [
- "env_logger 0.6.2",
+ "env_logger 0.7.0",
  "graphviz",
  "lazy_static 1.3.0",
  "log",
diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml
index 25f67b30468cc..9dc5c163fcc10 100644
--- a/src/librustc_driver/Cargo.toml
+++ b/src/librustc_driver/Cargo.toml
@@ -13,7 +13,7 @@ crate-type = ["dylib"]
 graphviz = { path = "../libgraphviz" }
 lazy_static = "1.0"
 log = "0.4"
-env_logger = { version = "0.6", default-features = false }
+env_logger = { version = "0.7", default-features = false }
 rustc = { path = "../librustc" }
 rustc_target = { path = "../librustc_target" }
 rustc_ast_borrowck = { path = "../librustc_ast_borrowck" }
diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml
index 745233c151cd6..80ef8dd662637 100644
--- a/src/tools/compiletest/Cargo.toml
+++ b/src/tools/compiletest/Cargo.toml
@@ -6,7 +6,7 @@ edition = "2018"
 
 [dependencies]
 diff = "0.1.10"
-env_logger = { version = "0.6", default-features = false }
+env_logger = { version = "0.7", default-features = false }
 getopts = "0.2"
 log = "0.4"
 regex = "1.0"

From 377a70d5ce78d798785d928469ac8e7fec57594f Mon Sep 17 00:00:00 2001
From: JMS55 <47158642+JMS55@users.noreply.github.com>
Date: Thu, 26 Sep 2019 11:19:59 -0400
Subject: [PATCH 04/24] Fix div_duration() marked as stable by mistake

---
 RELEASES.md | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/RELEASES.md b/RELEASES.md
index 766cf64410c77..e6512bb6f6de9 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -47,8 +47,6 @@ Stabilized APIs
 - [`<*mut T>::cast`]
 - [`Duration::as_secs_f32`]
 - [`Duration::as_secs_f64`]
-- [`Duration::div_duration_f32`]
-- [`Duration::div_duration_f64`]
 - [`Duration::div_f32`]
 - [`Duration::div_f64`]
 - [`Duration::from_secs_f32`]
@@ -100,8 +98,6 @@ Compatibility Notes
 [`<*mut T>::cast`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.cast
 [`Duration::as_secs_f32`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.as_secs_f32
 [`Duration::as_secs_f64`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.as_secs_f64
-[`Duration::div_duration_f32`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.div_duration_f32
-[`Duration::div_duration_f64`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.div_duration_f64
 [`Duration::div_f32`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.div_f32
 [`Duration::div_f64`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.div_f64
 [`Duration::from_secs_f32`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.from_secs_f32

From e79036d17fa8037f9f3f7e98a9b4ef80fb943ca7 Mon Sep 17 00:00:00 2001
From: David Wood <david@davidtw.co>
Date: Thu, 26 Sep 2019 11:00:53 +0100
Subject: [PATCH 05/24] hir: Disallow `target_feature` on constants

This commit fixes an ICE when `target_feature` is applied to constants.

Signed-off-by: David Wood <david@davidtw.co>
---
 src/librustc/hir/check_attr.rs                | 72 ++++++++++----
 src/test/ui/attributes/multiple-invalid.rs    | 10 ++
 .../ui/attributes/multiple-invalid.stderr     | 21 ++++
 src/test/ui/target-feature-wrong.stderr       | 50 ----------
 .../gate.rs}                                  |  0
 .../gate.stderr}                              |  2 +-
 .../invalid-attribute.rs}                     | 25 +++++
 .../target-feature/invalid-attribute.stderr   | 95 +++++++++++++++++++
 8 files changed, 204 insertions(+), 71 deletions(-)
 create mode 100644 src/test/ui/attributes/multiple-invalid.rs
 create mode 100644 src/test/ui/attributes/multiple-invalid.stderr
 delete mode 100644 src/test/ui/target-feature-wrong.stderr
 rename src/test/ui/{target-feature-gate.rs => target-feature/gate.rs} (100%)
 rename src/test/ui/{target-feature-gate.stderr => target-feature/gate.stderr} (91%)
 rename src/test/ui/{target-feature-wrong.rs => target-feature/invalid-attribute.rs} (62%)
 create mode 100644 src/test/ui/target-feature/invalid-attribute.stderr

diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs
index 1df09429e519f..283ab0103ec08 100644
--- a/src/librustc/hir/check_attr.rs
+++ b/src/librustc/hir/check_attr.rs
@@ -93,30 +93,35 @@ struct CheckAttrVisitor<'tcx> {
 impl CheckAttrVisitor<'tcx> {
     /// Checks any attribute.
     fn check_attributes(&self, item: &hir::Item, target: Target) {
-        if target == Target::Fn || target == Target::Const {
-            self.tcx.codegen_fn_attrs(self.tcx.hir().local_def_id(item.hir_id));
-        } else if let Some(a) = item.attrs.iter().find(|a| a.check_name(sym::target_feature)) {
-            self.tcx.sess.struct_span_err(a.span, "attribute should be applied to a function")
-                .span_label(item.span, "not a function")
-                .emit();
-        }
-
+        let mut is_valid = true;
         for attr in &item.attrs {
-            if attr.check_name(sym::inline) {
+            is_valid &= if attr.check_name(sym::inline) {
                 self.check_inline(attr, &item.span, target)
             } else if attr.check_name(sym::non_exhaustive) {
                 self.check_non_exhaustive(attr, item, target)
             } else if attr.check_name(sym::marker) {
                 self.check_marker(attr, item, target)
-            }
+            } else if attr.check_name(sym::target_feature) {
+                self.check_target_feature(attr, item, target)
+            } else {
+                true
+            };
+        }
+
+        if !is_valid {
+            return;
+        }
+
+        if target == Target::Fn || target == Target::Const {
+            self.tcx.codegen_fn_attrs(self.tcx.hir().local_def_id(item.hir_id));
         }
 
         self.check_repr(item, target);
         self.check_used(item, target);
     }
 
-    /// Checks if an `#[inline]` is applied to a function or a closure.
-    fn check_inline(&self, attr: &hir::Attribute, span: &Span, target: Target) {
+    /// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid.
+    fn check_inline(&self, attr: &hir::Attribute, span: &Span, target: Target) -> bool {
         if target != Target::Fn && target != Target::Closure {
             struct_span_err!(self.tcx.sess,
                              attr.span,
@@ -124,13 +129,21 @@ impl CheckAttrVisitor<'tcx> {
                              "attribute should be applied to function or closure")
                 .span_label(*span, "not a function or closure")
                 .emit();
+            false
+        } else {
+            true
         }
     }
 
-    /// Checks if the `#[non_exhaustive]` attribute on an `item` is valid.
-    fn check_non_exhaustive(&self, attr: &hir::Attribute, item: &hir::Item, target: Target) {
+    /// Checks if the `#[non_exhaustive]` attribute on an `item` is valid. Returns `true` if valid.
+    fn check_non_exhaustive(
+        &self,
+        attr: &hir::Attribute,
+        item: &hir::Item,
+        target: Target,
+    ) -> bool {
         match target {
-            Target::Struct | Target::Enum => { /* Valid */ },
+            Target::Struct | Target::Enum => true,
             _ => {
                 struct_span_err!(self.tcx.sess,
                                  attr.span,
@@ -138,25 +151,44 @@ impl CheckAttrVisitor<'tcx> {
                                  "attribute can only be applied to a struct or enum")
                     .span_label(item.span, "not a struct or enum")
                     .emit();
-                return;
+                false
             }
         }
     }
 
-    /// Checks if the `#[marker]` attribute on an `item` is valid.
-    fn check_marker(&self, attr: &hir::Attribute, item: &hir::Item, target: Target) {
+    /// Checks if the `#[marker]` attribute on an `item` is valid. Returns `true` if valid.
+    fn check_marker(&self, attr: &hir::Attribute, item: &hir::Item, target: Target) -> bool {
         match target {
-            Target::Trait => { /* Valid */ },
+            Target::Trait => true,
             _ => {
                 self.tcx.sess
                     .struct_span_err(attr.span, "attribute can only be applied to a trait")
                     .span_label(item.span, "not a trait")
                     .emit();
-                return;
+                false
             }
         }
     }
 
+    /// Checks if the `#[target_feature]` attribute on `item` is valid. Returns `true` if valid.
+    fn check_target_feature(
+        &self,
+        attr: &hir::Attribute,
+        item: &hir::Item,
+        target: Target,
+    ) -> bool {
+        match target {
+            Target::Fn => true,
+            _ => {
+                self.tcx.sess
+                    .struct_span_err(attr.span, "attribute should be applied to a function")
+                    .span_label(item.span, "not a function")
+                    .emit();
+                false
+            },
+        }
+    }
+
     /// Checks if the `#[repr]` attributes on `item` are valid.
     fn check_repr(&self, item: &hir::Item, target: Target) {
         // Extract the names of all repr hints, e.g., [foo, bar, align] for:
diff --git a/src/test/ui/attributes/multiple-invalid.rs b/src/test/ui/attributes/multiple-invalid.rs
new file mode 100644
index 0000000000000..ae044eb843bd9
--- /dev/null
+++ b/src/test/ui/attributes/multiple-invalid.rs
@@ -0,0 +1,10 @@
+// This test checks that all expected errors occur when there are multiple invalid attributes
+// on an item.
+
+#[inline]
+//~^ ERROR attribute should be applied to function or closure [E0518]
+#[target_feature(enable = "sse2")]
+//~^ ERROR attribute should be applied to a function
+const FOO: u8 = 0;
+
+fn main() { }
diff --git a/src/test/ui/attributes/multiple-invalid.stderr b/src/test/ui/attributes/multiple-invalid.stderr
new file mode 100644
index 0000000000000..9bd29f15dbcca
--- /dev/null
+++ b/src/test/ui/attributes/multiple-invalid.stderr
@@ -0,0 +1,21 @@
+error[E0518]: attribute should be applied to function or closure
+  --> $DIR/multiple-invalid.rs:4:1
+   |
+LL | #[inline]
+   | ^^^^^^^^^
+...
+LL | const FOO: u8 = 0;
+   | ------------------ not a function or closure
+
+error: attribute should be applied to a function
+  --> $DIR/multiple-invalid.rs:6:1
+   |
+LL | #[target_feature(enable = "sse2")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | const FOO: u8 = 0;
+   | ------------------ not a function
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0518`.
diff --git a/src/test/ui/target-feature-wrong.stderr b/src/test/ui/target-feature-wrong.stderr
deleted file mode 100644
index 47ca5a5ca478c..0000000000000
--- a/src/test/ui/target-feature-wrong.stderr
+++ /dev/null
@@ -1,50 +0,0 @@
-error: malformed `target_feature` attribute input
-  --> $DIR/target-feature-wrong.rs:16:1
-   |
-LL | #[target_feature = "+sse2"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[target_feature(enable = "name")]`
-
-error: the feature named `foo` is not valid for this target
-  --> $DIR/target-feature-wrong.rs:18:18
-   |
-LL | #[target_feature(enable = "foo")]
-   |                  ^^^^^^^^^^^^^^ `foo` is not valid for this target
-
-error: malformed `target_feature` attribute input
-  --> $DIR/target-feature-wrong.rs:21:18
-   |
-LL | #[target_feature(bar)]
-   |                  ^^^ help: must be of the form: `enable = ".."`
-
-error: malformed `target_feature` attribute input
-  --> $DIR/target-feature-wrong.rs:23:18
-   |
-LL | #[target_feature(disable = "baz")]
-   |                  ^^^^^^^^^^^^^^^ help: must be of the form: `enable = ".."`
-
-error: `#[target_feature(..)]` can only be applied to `unsafe` functions
-  --> $DIR/target-feature-wrong.rs:27:1
-   |
-LL | #[target_feature(enable = "sse2")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can only be applied to `unsafe` functions
-...
-LL | fn bar() {}
-   | ----------- not an `unsafe` function
-
-error: attribute should be applied to a function
-  --> $DIR/target-feature-wrong.rs:33:1
-   |
-LL | #[target_feature(enable = "sse2")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-LL |
-LL | mod another {}
-   | -------------- not a function
-
-error: cannot use `#[inline(always)]` with `#[target_feature]`
-  --> $DIR/target-feature-wrong.rs:38:1
-   |
-LL | #[inline(always)]
-   | ^^^^^^^^^^^^^^^^^
-
-error: aborting due to 7 previous errors
-
diff --git a/src/test/ui/target-feature-gate.rs b/src/test/ui/target-feature/gate.rs
similarity index 100%
rename from src/test/ui/target-feature-gate.rs
rename to src/test/ui/target-feature/gate.rs
diff --git a/src/test/ui/target-feature-gate.stderr b/src/test/ui/target-feature/gate.stderr
similarity index 91%
rename from src/test/ui/target-feature-gate.stderr
rename to src/test/ui/target-feature/gate.stderr
index 9f17110b6d874..05dbc6e90adc8 100644
--- a/src/test/ui/target-feature-gate.stderr
+++ b/src/test/ui/target-feature/gate.stderr
@@ -1,5 +1,5 @@
 error[E0658]: the target feature `avx512bw` is currently unstable
-  --> $DIR/target-feature-gate.rs:30:18
+  --> $DIR/gate.rs:30:18
    |
 LL | #[target_feature(enable = "avx512bw")]
    |                  ^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/target-feature-wrong.rs b/src/test/ui/target-feature/invalid-attribute.rs
similarity index 62%
rename from src/test/ui/target-feature-wrong.rs
rename to src/test/ui/target-feature/invalid-attribute.rs
index 646a98763e1b3..46680336632f9 100644
--- a/src/test/ui/target-feature-wrong.rs
+++ b/src/test/ui/target-feature/invalid-attribute.rs
@@ -35,6 +35,31 @@ fn bar() {}
 mod another {}
 //~^ NOTE not a function
 
+#[target_feature(enable = "sse2")]
+//~^ ERROR attribute should be applied to a function
+const FOO: usize = 7;
+//~^ NOTE not a function
+
+#[target_feature(enable = "sse2")]
+//~^ ERROR attribute should be applied to a function
+struct Foo;
+//~^ NOTE not a function
+
+#[target_feature(enable = "sse2")]
+//~^ ERROR attribute should be applied to a function
+enum Bar { }
+//~^ NOTE not a function
+
+#[target_feature(enable = "sse2")]
+//~^ ERROR attribute should be applied to a function
+union Qux { f1: u16, f2: u16 }
+//~^ NOTE not a function
+
+#[target_feature(enable = "sse2")]
+//~^ ERROR attribute should be applied to a function
+trait Baz { }
+//~^ NOTE not a function
+
 #[inline(always)]
 //~^ ERROR: cannot use `#[inline(always)]`
 #[target_feature(enable = "sse2")]
diff --git a/src/test/ui/target-feature/invalid-attribute.stderr b/src/test/ui/target-feature/invalid-attribute.stderr
new file mode 100644
index 0000000000000..abfe5dd219770
--- /dev/null
+++ b/src/test/ui/target-feature/invalid-attribute.stderr
@@ -0,0 +1,95 @@
+error: malformed `target_feature` attribute input
+  --> $DIR/invalid-attribute.rs:16:1
+   |
+LL | #[target_feature = "+sse2"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[target_feature(enable = "name")]`
+
+error: the feature named `foo` is not valid for this target
+  --> $DIR/invalid-attribute.rs:18:18
+   |
+LL | #[target_feature(enable = "foo")]
+   |                  ^^^^^^^^^^^^^^ `foo` is not valid for this target
+
+error: malformed `target_feature` attribute input
+  --> $DIR/invalid-attribute.rs:21:18
+   |
+LL | #[target_feature(bar)]
+   |                  ^^^ help: must be of the form: `enable = ".."`
+
+error: malformed `target_feature` attribute input
+  --> $DIR/invalid-attribute.rs:23:18
+   |
+LL | #[target_feature(disable = "baz")]
+   |                  ^^^^^^^^^^^^^^^ help: must be of the form: `enable = ".."`
+
+error: `#[target_feature(..)]` can only be applied to `unsafe` functions
+  --> $DIR/invalid-attribute.rs:27:1
+   |
+LL | #[target_feature(enable = "sse2")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can only be applied to `unsafe` functions
+...
+LL | fn bar() {}
+   | ----------- not an `unsafe` function
+
+error: attribute should be applied to a function
+  --> $DIR/invalid-attribute.rs:33:1
+   |
+LL | #[target_feature(enable = "sse2")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | mod another {}
+   | -------------- not a function
+
+error: attribute should be applied to a function
+  --> $DIR/invalid-attribute.rs:38:1
+   |
+LL | #[target_feature(enable = "sse2")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | const FOO: usize = 7;
+   | --------------------- not a function
+
+error: attribute should be applied to a function
+  --> $DIR/invalid-attribute.rs:43:1
+   |
+LL | #[target_feature(enable = "sse2")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | struct Foo;
+   | ----------- not a function
+
+error: attribute should be applied to a function
+  --> $DIR/invalid-attribute.rs:48:1
+   |
+LL | #[target_feature(enable = "sse2")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | enum Bar { }
+   | ------------ not a function
+
+error: attribute should be applied to a function
+  --> $DIR/invalid-attribute.rs:53:1
+   |
+LL | #[target_feature(enable = "sse2")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | union Qux { f1: u16, f2: u16 }
+   | ------------------------------ not a function
+
+error: attribute should be applied to a function
+  --> $DIR/invalid-attribute.rs:58:1
+   |
+LL | #[target_feature(enable = "sse2")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | trait Baz { }
+   | ------------- not a function
+
+error: cannot use `#[inline(always)]` with `#[target_feature]`
+  --> $DIR/invalid-attribute.rs:63:1
+   |
+LL | #[inline(always)]
+   | ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 12 previous errors
+

From c3368bdfa498f0c8fb2267dfb0cb804df8ec6dbb Mon Sep 17 00:00:00 2001
From: David Wood <david@davidtw.co>
Date: Thu, 26 Sep 2019 17:03:29 +0100
Subject: [PATCH 06/24] hir: stop checking codegen fn attrs for constants

See linked comment[1] for context.

1: https://github.com/rust-lang/rust/pull/64809#discussion_r328662933

Signed-off-by: David Wood <david@davidtw.co>
---
 src/librustc/hir/check_attr.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs
index 283ab0103ec08..fcd5378063190 100644
--- a/src/librustc/hir/check_attr.rs
+++ b/src/librustc/hir/check_attr.rs
@@ -112,7 +112,7 @@ impl CheckAttrVisitor<'tcx> {
             return;
         }
 
-        if target == Target::Fn || target == Target::Const {
+        if target == Target::Fn {
             self.tcx.codegen_fn_attrs(self.tcx.hir().local_def_id(item.hir_id));
         }
 

From 821ff468780176d3d668e67847f73e38b97ca9f8 Mon Sep 17 00:00:00 2001
From: Kenny Goodin <kennethbgoodin@gmail.com>
Date: Tue, 24 Sep 2019 14:20:52 -0400
Subject: [PATCH 07/24] Include message on tests that should panic

---
 src/libtest/lib.rs   | 1 +
 src/libtest/tests.rs | 4 ++--
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs
index e441514e59738..bcda5384204d8 100644
--- a/src/libtest/lib.rs
+++ b/src/libtest/lib.rs
@@ -1546,6 +1546,7 @@ fn calc_result(desc: &TestDesc, task_result: Result<(), Box<dyn Any + Send>>) ->
                 }
             }
         }
+        (&ShouldPanic::Yes, Ok(())) => TrFailedMsg("test did not panic as expected".to_string()),
         _ if desc.allow_fail => TrAllowedFail,
         _ => TrFailed,
     }
diff --git a/src/libtest/tests.rs b/src/libtest/tests.rs
index 13ac8eb91f411..38ec7bd70930c 100644
--- a/src/libtest/tests.rs
+++ b/src/libtest/tests.rs
@@ -2,7 +2,7 @@ use super::*;
 
 use crate::test::{
     filter_tests, parse_opts, run_test, DynTestFn, DynTestName, MetricMap, RunIgnored,
-    ShouldPanic, StaticTestName, TestDesc, TestDescAndFn, TestOpts, TrFailed, TrFailedMsg,
+    ShouldPanic, StaticTestName, TestDesc, TestDescAndFn, TestOpts, TrFailedMsg,
     TrIgnored, TrOk,
 };
 use std::sync::mpsc::channel;
@@ -167,7 +167,7 @@ fn test_should_panic_but_succeeds() {
     let (tx, rx) = channel();
     run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
     let (_, res, _, _) = rx.recv().unwrap();
-    assert!(res == TrFailed);
+    assert!(res == TrFailedMsg("test did not panic as expected".to_string()));
 }
 
 fn report_time_test_template(report_time: bool) -> Option<TestExecTime> {

From 9ef6edb04ad059242551f134077dab88a36bdd61 Mon Sep 17 00:00:00 2001
From: Mazdak Farrokhzad <twingoow@gmail.com>
Date: Fri, 27 Sep 2019 06:09:32 +0200
Subject: [PATCH 08/24] lowering: don't .abort_if_errors()

---
 src/librustc/hir/lowering/expr.rs                 |  3 +--
 .../ui/generator/no-parameters-on-generators.rs   |  1 +
 .../generator/no-parameters-on-generators.stderr  | 15 ++++++++++++++-
 3 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/src/librustc/hir/lowering/expr.rs b/src/librustc/hir/lowering/expr.rs
index 90b6c9474acb0..56a7b88ab06ce 100644
--- a/src/librustc/hir/lowering/expr.rs
+++ b/src/librustc/hir/lowering/expr.rs
@@ -705,7 +705,6 @@ impl LoweringContext<'_> {
                         E0628,
                         "generators cannot have explicit parameters"
                     );
-                    self.sess.abort_if_errors();
                 }
                 Some(match movability {
                     Movability::Movable => hir::GeneratorMovability::Movable,
@@ -998,7 +997,7 @@ impl LoweringContext<'_> {
                     E0727,
                     "`async` generators are not yet supported",
                 );
-                self.sess.abort_if_errors();
+                return hir::ExprKind::Err;
             },
             None => self.generator_kind = Some(hir::GeneratorKind::Gen),
         }
diff --git a/src/test/ui/generator/no-parameters-on-generators.rs b/src/test/ui/generator/no-parameters-on-generators.rs
index a2632a4bd7d84..6b5a557933953 100644
--- a/src/test/ui/generator/no-parameters-on-generators.rs
+++ b/src/test/ui/generator/no-parameters-on-generators.rs
@@ -2,6 +2,7 @@
 
 fn main() {
     let gen = |start| { //~ ERROR generators cannot have explicit parameters
+        //~^ ERROR type inside generator must be known in this context
         yield;
     };
 }
diff --git a/src/test/ui/generator/no-parameters-on-generators.stderr b/src/test/ui/generator/no-parameters-on-generators.stderr
index 41862f2b0704b..5e8e043a391ce 100644
--- a/src/test/ui/generator/no-parameters-on-generators.stderr
+++ b/src/test/ui/generator/no-parameters-on-generators.stderr
@@ -4,5 +4,18 @@ error[E0628]: generators cannot have explicit parameters
 LL |     let gen = |start| {
    |               ^^^^^^^
 
-error: aborting due to previous error
+error[E0698]: type inside generator must be known in this context
+  --> $DIR/no-parameters-on-generators.rs:4:16
+   |
+LL |     let gen = |start| {
+   |                ^^^^^ cannot infer type
+   |
+note: the type is part of the generator because of this `yield`
+  --> $DIR/no-parameters-on-generators.rs:6:9
+   |
+LL |         yield;
+   |         ^^^^^
+
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0698`.

From c482c84142e4f4194a50c1fda4dbd311759bae41 Mon Sep 17 00:00:00 2001
From: Lzu Tao <taolzu@gmail.com>
Date: Fri, 27 Sep 2019 11:21:57 +0000
Subject: [PATCH 09/24] Stabilize map_get_key_value feature

---
 src/liballoc/collections/btree/map.rs | 3 +--
 src/libstd/collections/hash/map.rs    | 3 +--
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs
index 1683b8105567f..ddf012d15029a 100644
--- a/src/liballoc/collections/btree/map.rs
+++ b/src/liballoc/collections/btree/map.rs
@@ -580,7 +580,6 @@ impl<K: Ord, V> BTreeMap<K, V> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(map_get_key_value)]
     /// use std::collections::BTreeMap;
     ///
     /// let mut map = BTreeMap::new();
@@ -588,7 +587,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
     /// assert_eq!(map.get_key_value(&1), Some((&1, &"a")));
     /// assert_eq!(map.get_key_value(&2), None);
     /// ```
-    #[unstable(feature = "map_get_key_value", issue = "49347")]
+    #[stable(feature = "map_get_key_value", since = "1.40.0")]
     pub fn get_key_value<Q: ?Sized>(&self, k: &Q) -> Option<(&K, &V)>
         where K: Borrow<Q>,
               Q: Ord
diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs
index a0538986a2242..69abbde9e6eba 100644
--- a/src/libstd/collections/hash/map.rs
+++ b/src/libstd/collections/hash/map.rs
@@ -714,7 +714,6 @@ where
     /// # Examples
     ///
     /// ```
-    /// #![feature(map_get_key_value)]
     /// use std::collections::HashMap;
     ///
     /// let mut map = HashMap::new();
@@ -722,7 +721,7 @@ where
     /// assert_eq!(map.get_key_value(&1), Some((&1, &"a")));
     /// assert_eq!(map.get_key_value(&2), None);
     /// ```
-    #[unstable(feature = "map_get_key_value", issue = "49347")]
+    #[stable(feature = "map_get_key_value", since = "1.40.0")]
     #[inline]
     pub fn get_key_value<Q: ?Sized>(&self, k: &Q) -> Option<(&K, &V)>
     where

From bd995c0e3a303c4685d69ff560ad470fc5197c1e Mon Sep 17 00:00:00 2001
From: rusty-snake <print_hello_world+Public@protonmail.com>
Date: Fri, 27 Sep 2019 14:33:08 +0000
Subject: [PATCH 10/24] pin.rs: fix links to primitives in documentation

---
 src/libcore/pin.rs | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs
index 1dc6d54b08a5a..be057ed6d59a7 100644
--- a/src/libcore/pin.rs
+++ b/src/libcore/pin.rs
@@ -369,6 +369,8 @@
 //! [drop-guarantee]: #drop-guarantee
 //! [`poll`]: ../../std/future/trait.Future.html#tymethod.poll
 //! [`Pin::get_unchecked_mut`]: struct.Pin.html#method.get_unchecked_mut
+//! [`bool`]: ../../std/primitive.bool.html
+//! [`i32`]: ../../std/primitive.i32.html
 
 #![stable(feature = "pin", since = "1.33.0")]
 

From 115437421c32bdde517f522f7e15bcc11085a63a Mon Sep 17 00:00:00 2001
From: Eduard-Mihai Burtescu <edy.burt@gmail.com>
Date: Sat, 10 Aug 2019 13:29:39 +0300
Subject: [PATCH 11/24] syntax: don't keep a redundant c_variadic flag in the
 AST.

---
 src/librustc/hir/lowering.rs                  |  2 +-
 src/librustc/hir/lowering/expr.rs             |  2 --
 src/libsyntax/ast.rs                          |  7 ++++++-
 src/libsyntax/ext/build.rs                    |  1 -
 src/libsyntax/feature_gate/check.rs           | 11 ++++++++---
 src/libsyntax/mut_visit.rs                    |  2 +-
 src/libsyntax/parse/parser.rs                 |  7 ++++---
 src/libsyntax/parse/parser/expr.rs            |  1 -
 src/libsyntax/parse/parser/item.rs            |  3 +--
 src/libsyntax/parse/parser/ty.rs              |  3 +--
 src/libsyntax/print/pprust/tests.rs           |  1 -
 src/test/ui-fulldeps/pprust-expr-roundtrip.rs |  1 -
 12 files changed, 22 insertions(+), 19 deletions(-)

diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index d0a9d967a649d..aa2b4b103fb81 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -2168,7 +2168,7 @@ impl<'a> LoweringContext<'a> {
         P(hir::FnDecl {
             inputs,
             output,
-            c_variadic: decl.c_variadic,
+            c_variadic: decl.c_variadic(),
             implicit_self: decl.inputs.get(0).map_or(
                 hir::ImplicitSelfKind::None,
                 |arg| {
diff --git a/src/librustc/hir/lowering/expr.rs b/src/librustc/hir/lowering/expr.rs
index caecc162c7866..7ce1fa132a8a9 100644
--- a/src/librustc/hir/lowering/expr.rs
+++ b/src/librustc/hir/lowering/expr.rs
@@ -450,7 +450,6 @@ impl LoweringContext<'_> {
         let ast_decl = FnDecl {
             inputs: vec![],
             output,
-            c_variadic: false
         };
         let decl = self.lower_fn_decl(&ast_decl, None, /* impl trait allowed */ false, None);
         let body_id = self.lower_fn_body(&ast_decl, |this| {
@@ -740,7 +739,6 @@ impl LoweringContext<'_> {
         let outer_decl = FnDecl {
             inputs: decl.inputs.clone(),
             output: FunctionRetTy::Default(fn_decl_span),
-            c_variadic: false,
         };
         // We need to lower the declaration outside the new scope, because we
         // have to conserve the state of being inside a loop condition for the
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index a7f035dc9ecc7..bc468c1ad0ebe 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1893,7 +1893,6 @@ impl Param {
 pub struct FnDecl {
     pub inputs: Vec<Param>,
     pub output: FunctionRetTy,
-    pub c_variadic: bool,
 }
 
 impl FnDecl {
@@ -1903,6 +1902,12 @@ impl FnDecl {
     pub fn has_self(&self) -> bool {
         self.inputs.get(0).map(Param::is_self).unwrap_or(false)
     }
+    pub fn c_variadic(&self) -> bool {
+        self.inputs.last().map(|arg| match arg.ty.kind {
+            TyKind::CVarArgs => true,
+            _ => false,
+        }).unwrap_or(false)
+    }
 }
 
 /// Is the trait definition an auto trait?
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 6b93d045588b9..8c5289671c98e 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -562,7 +562,6 @@ impl<'a> ExtCtxt<'a> {
         P(ast::FnDecl {
             inputs,
             output,
-            c_variadic: false
         })
     }
 
diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs
index 622b48ab9281e..d7fc74955bbbd 100644
--- a/src/libsyntax/feature_gate/check.rs
+++ b/src/libsyntax/feature_gate/check.rs
@@ -531,7 +531,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             self.check_abi(header.abi, span);
         }
 
-        if fn_decl.c_variadic {
+        if fn_decl.c_variadic() {
             gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable");
         }
 
@@ -564,7 +564,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                 if block.is_none() {
                     self.check_abi(sig.header.abi, ti.span);
                 }
-                if sig.decl.c_variadic {
+                if sig.decl.c_variadic() {
                     gate_feature_post!(&self, c_variadic, ti.span,
                                        "C-variadic functions are unstable");
                 }
@@ -601,7 +601,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
         }
 
         match ii.kind {
-            ast::ImplItemKind::Method(..) => {}
+            ast::ImplItemKind::Method(ref sig, _) => {
+                if sig.decl.c_variadic() {
+                    gate_feature_post!(&self, c_variadic, ii.span,
+                                       "C-variadic functions are unstable");
+                }
+            }
             ast::ImplItemKind::OpaqueTy(..) => {
                 gate_feature_post!(
                     &self,
diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs
index 43b5df38e143c..80dfe9e5be0ad 100644
--- a/src/libsyntax/mut_visit.rs
+++ b/src/libsyntax/mut_visit.rs
@@ -717,7 +717,7 @@ pub fn noop_visit_asyncness<T: MutVisitor>(asyncness: &mut IsAsync, vis: &mut T)
 }
 
 pub fn noop_visit_fn_decl<T: MutVisitor>(decl: &mut P<FnDecl>, vis: &mut T) {
-    let FnDecl { inputs, output, c_variadic: _ } = decl.deref_mut();
+    let FnDecl { inputs, output } = decl.deref_mut();
     inputs.flat_map_in_place(|param| vis.flat_map_param(param));
     match output {
         FunctionRetTy::Default(span) => vis.visit_span(span),
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index cc582819b6b61..f22fd5ad703d9 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -1194,7 +1194,7 @@ impl<'a> Parser<'a> {
     }
 
     fn parse_fn_params(&mut self, named_params: bool, allow_c_variadic: bool)
-                     -> PResult<'a, (Vec<Param> , bool)> {
+                     -> PResult<'a, Vec<Param>> {
         let sp = self.token.span;
         let mut c_variadic = false;
         let (params, _): (Vec<Option<Param>>, _) = self.parse_paren_comma_seq(|p| {
@@ -1218,6 +1218,8 @@ impl<'a> Parser<'a> {
                             let span = p.token.span;
                             p.span_err(span,
                                 "`...` must be the last argument of a C-variadic function");
+                            // FIXME(eddyb) this should probably still push `CVarArgs`.
+                            // Maybe AST validation/HIR lowering should emit the above error?
                             Ok(None)
                         } else {
                             Ok(Some(param))
@@ -1245,7 +1247,7 @@ impl<'a> Parser<'a> {
                           "C-variadic function must be declared with at least one named argument");
         }
 
-        Ok((params, c_variadic))
+        Ok(params)
     }
 
     /// Returns the parsed optional self parameter and whether a self shortcut was used.
@@ -1414,7 +1416,6 @@ impl<'a> Parser<'a> {
         Ok(P(FnDecl {
             inputs: fn_inputs,
             output: self.parse_ret_ty(true)?,
-            c_variadic: false
         }))
     }
 
diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs
index c776704b285aa..23674ad589dc5 100644
--- a/src/libsyntax/parse/parser/expr.rs
+++ b/src/libsyntax/parse/parser/expr.rs
@@ -1176,7 +1176,6 @@ impl<'a> Parser<'a> {
         Ok(P(FnDecl {
             inputs: inputs_captures,
             output,
-            c_variadic: false
         }))
     }
 
diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs
index 370030d02c717..92b19b73e5719 100644
--- a/src/libsyntax/parse/parser/item.rs
+++ b/src/libsyntax/parse/parser/item.rs
@@ -1292,13 +1292,12 @@ impl<'a> Parser<'a> {
 
     /// Parses the argument list and result type of a function declaration.
     fn parse_fn_decl(&mut self, allow_c_variadic: bool) -> PResult<'a, P<FnDecl>> {
-        let (args, c_variadic) = self.parse_fn_params(true, allow_c_variadic)?;
+        let args = self.parse_fn_params(true, allow_c_variadic)?;
         let ret_ty = self.parse_ret_ty(true)?;
 
         Ok(P(FnDecl {
             inputs: args,
             output: ret_ty,
-            c_variadic,
         }))
     }
 
diff --git a/src/libsyntax/parse/parser/ty.rs b/src/libsyntax/parse/parser/ty.rs
index b4c006ca2b119..c52d3733b5e0a 100644
--- a/src/libsyntax/parse/parser/ty.rs
+++ b/src/libsyntax/parse/parser/ty.rs
@@ -292,12 +292,11 @@ impl<'a> Parser<'a> {
         };
 
         self.expect_keyword(kw::Fn)?;
-        let (inputs, c_variadic) = self.parse_fn_params(false, true)?;
+        let inputs = self.parse_fn_params(false, true)?;
         let ret_ty = self.parse_ret_ty(false)?;
         let decl = P(FnDecl {
             inputs,
             output: ret_ty,
-            c_variadic,
         });
         Ok(TyKind::BareFn(P(BareFnTy {
             abi,
diff --git a/src/libsyntax/print/pprust/tests.rs b/src/libsyntax/print/pprust/tests.rs
index 05d78cdd87ec6..faa70edbfa29b 100644
--- a/src/libsyntax/print/pprust/tests.rs
+++ b/src/libsyntax/print/pprust/tests.rs
@@ -29,7 +29,6 @@ fn test_fun_to_string() {
         let decl = ast::FnDecl {
             inputs: Vec::new(),
             output: ast::FunctionRetTy::Default(syntax_pos::DUMMY_SP),
-            c_variadic: false
         };
         let generics = ast::Generics::default();
         assert_eq!(
diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs
index 784f71a61fd72..d4aff73590734 100644
--- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs
+++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs
@@ -114,7 +114,6 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
                 let decl = P(FnDecl {
                     inputs: vec![],
                     output: FunctionRetTy::Default(DUMMY_SP),
-                    c_variadic: false,
                 });
                 iter_exprs(depth - 1, &mut |e| g(
                         ExprKind::Closure(CaptureBy::Value,

From 8522997ee134fc0fb5677d9dae4d55e3d4982ec0 Mon Sep 17 00:00:00 2001
From: Eduard-Mihai Burtescu <edy.burt@gmail.com>
Date: Sun, 11 Aug 2019 18:34:31 +0300
Subject: [PATCH 12/24] rustc: don't store a lifetime in hir::TyKind::CVarArgs.

---
 src/librustc/hir/intravisit.rs               |  4 +---
 src/librustc/hir/lowering.rs                 |  7 +------
 src/librustc/hir/mod.rs                      |  2 +-
 src/librustc/hir/print.rs                    |  2 +-
 src/librustc/middle/resolve_lifetime.rs      |  8 --------
 src/librustc_typeck/astconv.rs               |  7 +++++--
 src/librustdoc/clean/mod.rs                  |  2 +-
 src/test/ui/c-variadic/variadic-ffi-4.stderr | 16 ++++++++--------
 8 files changed, 18 insertions(+), 30 deletions(-)

diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index d1ebdd2f086ab..d7b5462da275b 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -633,9 +633,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
         TyKind::Typeof(ref expression) => {
             visitor.visit_anon_const(expression)
         }
-        TyKind::CVarArgs(ref lt) => {
-            visitor.visit_lifetime(lt)
-        }
+        TyKind::CVarArgs |
         TyKind::Infer | TyKind::Err => {}
     }
 }
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index aa2b4b103fb81..d9b444f52281b 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -1336,12 +1336,7 @@ impl<'a> LoweringContext<'a> {
                 }
             }
             TyKind::Mac(_) => bug!("`TyMac` should have been expanded by now"),
-            TyKind::CVarArgs => {
-                // Create the implicit lifetime of the "spoofed" `VaListImpl`.
-                let span = self.sess.source_map().next_point(t.span.shrink_to_lo());
-                let lt = self.new_implicit_lifetime(span);
-                hir::TyKind::CVarArgs(lt)
-            },
+            TyKind::CVarArgs => hir::TyKind::CVarArgs,
         };
 
         hir::Ty {
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 01cb5cc9bc105..8adf67c04270b 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -2029,7 +2029,7 @@ pub enum TyKind {
     Err,
     /// Placeholder for C-variadic arguments. We "spoof" the `VaListImpl` created
     /// from the variadic arguments. This type is only valid up to typeck.
-    CVarArgs(Lifetime),
+    CVarArgs,
 }
 
 #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 91f2c5a0aaf85..45cce24381b0b 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -361,7 +361,7 @@ impl<'a> State<'a> {
                 self.s.word("/*ERROR*/");
                 self.pclose();
             }
-            hir::TyKind::CVarArgs(_) => {
+            hir::TyKind::CVarArgs => {
                 self.s.word("...");
             }
         }
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 94a85a97d36c9..31d250fa08215 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -764,13 +764,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     });
                 }
             }
-            hir::TyKind::CVarArgs(ref lt) => {
-                // Resolve the generated lifetime for the C-variadic arguments.
-                // The lifetime is generated in AST -> HIR lowering.
-                if lt.name.is_elided() {
-                    self.resolve_elided_lifetimes(vec![lt])
-                }
-            }
             _ => intravisit::walk_ty(self, ty),
         }
     }
@@ -2378,7 +2371,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                             self.visit_lifetime(lifetime);
                         }
                     }
-                    hir::TyKind::CVarArgs(_) => {}
                     _ => {
                         intravisit::walk_ty(self, ty);
                     }
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 6f1d854481a10..5021277e04a2b 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -2151,13 +2151,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 // handled specially and will not descend into this routine.
                 self.ty_infer(None, ast_ty.span)
             }
-            hir::TyKind::CVarArgs(lt) => {
+            hir::TyKind::CVarArgs => {
                 let va_list_did = match tcx.lang_items().va_list() {
                     Some(did) => did,
                     None => span_bug!(ast_ty.span,
                                       "`va_list` lang item required for variadics"),
                 };
-                let region = self.ast_region_to_region(&lt, None);
+                // FIXME(eddyb) compute this in the body and don't let it reach the signature.
+                // HACK(eddyb) the `123` anon index is only temporary, to keep tests passing.
+                // Ideally this would use `ReScope` or similar.
+                let region = tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BrAnon(123)));
                 tcx.type_of(va_list_did).subst(tcx, &[region.into()])
             }
             hir::TyKind::Err => {
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index ce21447105815..24d017147e4c6 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -3032,7 +3032,7 @@ impl Clean<Type> for hir::Ty {
             TyKind::BareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
             TyKind::Infer | TyKind::Err => Infer,
             TyKind::Typeof(..) => panic!("unimplemented type {:?}", self.kind),
-            TyKind::CVarArgs(_) => CVarArgs,
+            TyKind::CVarArgs => CVarArgs,
         }
     }
 }
diff --git a/src/test/ui/c-variadic/variadic-ffi-4.stderr b/src/test/ui/c-variadic/variadic-ffi-4.stderr
index 7aa510e611304..3b7eb26c0732e 100644
--- a/src/test/ui/c-variadic/variadic-ffi-4.stderr
+++ b/src/test/ui/c-variadic/variadic-ffi-4.stderr
@@ -47,7 +47,7 @@ LL |     *ap0 = ap1;
    |
    = note: expected type `core::ffi::VaListImpl<'_>`
               found type `core::ffi::VaListImpl<'_>`
-note: the anonymous lifetime #3 defined on the function body at 19:1...
+note: the anonymous lifetime #124 defined on the function body at 19:1...
   --> $DIR/variadic-ffi-4.rs:19:1
    |
 LL | / pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
@@ -80,7 +80,7 @@ LL | |     *ap0 = ap1;
 LL | |
 LL | | }
    | |_^
-note: ...does not necessarily outlive the anonymous lifetime #3 defined on the function body at 19:1
+note: ...does not necessarily outlive the anonymous lifetime #124 defined on the function body at 19:1
   --> $DIR/variadic-ffi-4.rs:19:1
    |
 LL | / pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
@@ -106,7 +106,7 @@ LL | |
 LL | |
 LL | | }
    | |_^
-note: but the borrow lasts for the anonymous lifetime #3 defined on the function body at 24:1
+note: but the borrow lasts for the anonymous lifetime #124 defined on the function body at 24:1
   --> $DIR/variadic-ffi-4.rs:24:1
    |
 LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) {
@@ -126,7 +126,7 @@ LL |     ap0 = &mut ap1;
    |
    = note: expected type `&mut core::ffi::VaListImpl<'_>`
               found type `&mut core::ffi::VaListImpl<'_>`
-note: the anonymous lifetime #3 defined on the function body at 24:1...
+note: the anonymous lifetime #124 defined on the function body at 24:1...
   --> $DIR/variadic-ffi-4.rs:24:1
    |
 LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) {
@@ -168,7 +168,7 @@ LL | |
 LL | |
 LL | | }
    | |_^
-note: ...does not necessarily outlive the anonymous lifetime #3 defined on the function body at 24:1
+note: ...does not necessarily outlive the anonymous lifetime #124 defined on the function body at 24:1
   --> $DIR/variadic-ffi-4.rs:24:1
    |
 LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) {
@@ -186,7 +186,7 @@ error[E0495]: cannot infer an appropriate lifetime for borrow expression due to
 LL |     ap0 = &mut ap1;
    |           ^^^^^^^^
    |
-note: first, the lifetime cannot outlive the anonymous lifetime #3 defined on the function body at 24:1...
+note: first, the lifetime cannot outlive the anonymous lifetime #124 defined on the function body at 24:1...
   --> $DIR/variadic-ffi-4.rs:24:1
    |
 LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) {
@@ -227,7 +227,7 @@ LL |     *ap0 = ap1.clone();
    |
    = note: expected type `core::ffi::VaListImpl<'_>`
               found type `core::ffi::VaListImpl<'_>`
-note: the anonymous lifetime #3 defined on the function body at 32:1...
+note: the anonymous lifetime #124 defined on the function body at 32:1...
   --> $DIR/variadic-ffi-4.rs:32:1
    |
 LL | / pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
@@ -260,7 +260,7 @@ LL | |     *ap0 = ap1.clone();
 LL | |
 LL | | }
    | |_^
-note: ...does not necessarily outlive the anonymous lifetime #3 defined on the function body at 32:1
+note: ...does not necessarily outlive the anonymous lifetime #124 defined on the function body at 32:1
   --> $DIR/variadic-ffi-4.rs:32:1
    |
 LL | / pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {

From 072cf41bc9f5be8ce5f657097a714ecc0c862ef5 Mon Sep 17 00:00:00 2001
From: Eduard-Mihai Burtescu <edy.burt@gmail.com>
Date: Sat, 10 Aug 2019 14:38:17 +0300
Subject: [PATCH 13/24] rustc: rely on c_variadic == true instead of CVarArgs
 in HIR/Ty fn signatures.

---
 src/librustc/hir/intravisit.rs                |   1 -
 src/librustc/hir/lowering.rs                  |  26 ++-
 src/librustc/hir/mod.rs                       |   3 -
 src/librustc/hir/print.rs                     |   3 -
 src/librustc/ty/layout.rs                     |  35 +--
 src/librustc_codegen_llvm/abi.rs              |  12 +-
 src/librustc_codegen_ssa/mir/block.rs         |  32 +--
 src/librustc_codegen_ssa/mir/mod.rs           |  58 ++---
 src/librustc_lint/types.rs                    |   9 +-
 .../nll/type_check/input_output.rs            |  20 +-
 .../borrow_check/nll/type_check/mod.rs        |  11 +-
 .../borrow_check/nll/universal_regions.rs     |  10 +
 src/librustc_mir/build/mod.rs                 |  25 ++-
 src/librustc_target/abi/call/mod.rs           |  14 +-
 src/librustc_target/abi/call/x86.rs           |   2 +-
 src/librustc_typeck/astconv.rs                |  12 --
 src/librustc_typeck/check/callee.rs           |  14 +-
 src/librustc_typeck/check/mod.rs              |  23 +-
 src/librustdoc/clean/mod.rs                   |   8 +-
 src/librustdoc/html/format.rs                 |  15 +-
 src/test/rustdoc/variadic.rs                  |   2 +-
 src/test/ui/c-variadic/variadic-ffi-1.stderr  |   4 +-
 src/test/ui/c-variadic/variadic-ffi-4.rs      |  11 +-
 src/test/ui/c-variadic/variadic-ffi-4.stderr  | 199 ++++++------------
 src/test/ui/error-codes/E0617.rs              |   6 +-
 src/test/ui/error-codes/E0617.stderr          |  20 +-
 src/test/ui/symbol-names/impl1.legacy.stderr  |  16 +-
 src/test/ui/symbol-names/impl1.rs             |  20 +-
 src/test/ui/symbol-names/impl1.v0.stderr      |  16 +-
 29 files changed, 267 insertions(+), 360 deletions(-)

diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index d7b5462da275b..05bdd0887f0f6 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -633,7 +633,6 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
         TyKind::Typeof(ref expression) => {
             visitor.visit_anon_const(expression)
         }
-        TyKind::CVarArgs |
         TyKind::Infer | TyKind::Err => {}
     }
 }
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index d9b444f52281b..6f51e05881be5 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -1335,8 +1335,8 @@ impl<'a> LoweringContext<'a> {
                     }
                 }
             }
-            TyKind::Mac(_) => bug!("`TyMac` should have been expanded by now"),
-            TyKind::CVarArgs => hir::TyKind::CVarArgs,
+            TyKind::Mac(_) => bug!("`TyKind::Mac` should have been expanded by now"),
+            TyKind::CVarArgs => bug!("`TyKind::CVarArgs` should have been handled elsewhere"),
         };
 
         hir::Ty {
@@ -2088,7 +2088,14 @@ impl<'a> LoweringContext<'a> {
     }
 
     fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> hir::HirVec<Ident> {
-        decl.inputs
+        // Skip the `...` (`CVarArgs`) trailing arguments from the AST,
+        // as they are not explicit in HIR/Ty function signatures.
+        // (instead, the `c_variadic` flag is set to `true`)
+        let mut inputs = &decl.inputs[..];
+        if decl.c_variadic() {
+            inputs = &inputs[..inputs.len() - 1];
+        }
+        inputs
             .iter()
             .map(|param| match param.pat.kind {
                 PatKind::Ident(_, ident, _) => ident,
@@ -2125,10 +2132,19 @@ impl<'a> LoweringContext<'a> {
             self.anonymous_lifetime_mode
         };
 
+        let c_variadic = decl.c_variadic();
+
         // Remember how many lifetimes were already around so that we can
         // only look at the lifetime parameters introduced by the arguments.
         let inputs = self.with_anonymous_lifetime_mode(lt_mode, |this| {
-            decl.inputs
+            // Skip the `...` (`CVarArgs`) trailing arguments from the AST,
+            // as they are not explicit in HIR/Ty function signatures.
+            // (instead, the `c_variadic` flag is set to `true`)
+            let mut inputs = &decl.inputs[..];
+            if c_variadic {
+                inputs = &inputs[..inputs.len() - 1];
+            }
+            inputs
                 .iter()
                 .map(|param| {
                     if let Some((_, ibty)) = &mut in_band_ty_params {
@@ -2163,7 +2179,7 @@ impl<'a> LoweringContext<'a> {
         P(hir::FnDecl {
             inputs,
             output,
-            c_variadic: decl.c_variadic(),
+            c_variadic,
             implicit_self: decl.inputs.get(0).map_or(
                 hir::ImplicitSelfKind::None,
                 |arg| {
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 8adf67c04270b..7ab754f0a0e68 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -2027,9 +2027,6 @@ pub enum TyKind {
     Infer,
     /// Placeholder for a type that has failed to be defined.
     Err,
-    /// Placeholder for C-variadic arguments. We "spoof" the `VaListImpl` created
-    /// from the variadic arguments. This type is only valid up to typeck.
-    CVarArgs,
 }
 
 #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 45cce24381b0b..6cffaa8a494c4 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -361,9 +361,6 @@ impl<'a> State<'a> {
                 self.s.word("/*ERROR*/");
                 self.pclose();
             }
-            hir::TyKind::CVarArgs => {
-                self.s.word("...");
-            }
         }
         self.end()
     }
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 790b0c5cb48f4..61cb3a0d4667d 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -25,7 +25,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
 pub use rustc_target::abi::*;
 use rustc_target::spec::{HasTargetSpec, abi::Abi as SpecAbi};
 use rustc_target::abi::call::{
-    ArgAttribute, ArgAttributes, ArgType, Conv, FnType, IgnoreMode, PassMode, Reg, RegKind
+    ArgAttribute, ArgAttributes, ArgType, Conv, FnType, PassMode, Reg, RegKind
 };
 
 pub trait IntegerExt {
@@ -2722,14 +2722,6 @@ where
             }
         };
 
-        // Store the index of the last argument. This is useful for working with
-        // C-compatible variadic arguments.
-        let last_arg_idx = if sig.inputs().is_empty() {
-            None
-        } else {
-            Some(sig.inputs().len() - 1)
-        };
-
         let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| {
             let is_return = arg_idx.is_none();
             let mut arg = mk_arg_type(ty, arg_idx);
@@ -2739,30 +2731,7 @@ where
                 // The same is true for s390x-unknown-linux-gnu
                 // and sparc64-unknown-linux-gnu.
                 if is_return || rust_abi || (!win_x64_gnu && !linux_s390x && !linux_sparc64) {
-                    arg.mode = PassMode::Ignore(IgnoreMode::Zst);
-                }
-            }
-
-            // If this is a C-variadic function, this is not the return value,
-            // and there is one or more fixed arguments; ensure that the `VaListImpl`
-            // is ignored as an argument.
-            if sig.c_variadic {
-                match (last_arg_idx, arg_idx) {
-                    (Some(last_idx), Some(cur_idx)) if last_idx == cur_idx => {
-                        let va_list_did = match cx.tcx().lang_items().va_list() {
-                            Some(did) => did,
-                            None => bug!("`va_list` lang item required for C-variadic functions"),
-                        };
-                        match ty.kind {
-                            ty::Adt(def, _) if def.did == va_list_did => {
-                                // This is the "spoofed" `VaListImpl`. Set the arguments mode
-                                // so that it will be ignored.
-                                arg.mode = PassMode::Ignore(IgnoreMode::CVarArgs);
-                            }
-                            _ => (),
-                        }
-                    }
-                    _ => {}
+                    arg.mode = PassMode::Ignore;
                 }
             }
 
diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs
index 2ca517dc3b1a7..ae5cfc4d97b59 100644
--- a/src/librustc_codegen_llvm/abi.rs
+++ b/src/librustc_codegen_llvm/abi.rs
@@ -264,7 +264,7 @@ impl ArgTypeExt<'ll, 'tcx> for ArgType<'tcx, Ty<'tcx>> {
             val
         };
         match self.mode {
-            PassMode::Ignore(_) => {}
+            PassMode::Ignore => {}
             PassMode::Pair(..) => {
                 OperandValue::Pair(next(), next()).store(bx, dst);
             }
@@ -319,9 +319,7 @@ impl<'tcx> FnTypeLlvmExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
         );
 
         let llreturn_ty = match self.ret.mode {
-            PassMode::Ignore(IgnoreMode::Zst) => cx.type_void(),
-            PassMode::Ignore(IgnoreMode::CVarArgs) =>
-                bug!("`va_list` should never be a return type"),
+            PassMode::Ignore => cx.type_void(),
             PassMode::Direct(_) | PassMode::Pair(..) => {
                 self.ret.layout.immediate_llvm_type(cx)
             }
@@ -339,7 +337,7 @@ impl<'tcx> FnTypeLlvmExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
             }
 
             let llarg_ty = match arg.mode {
-                PassMode::Ignore(_) => continue,
+                PassMode::Ignore => continue,
                 PassMode::Direct(_) => arg.layout.immediate_llvm_type(cx),
                 PassMode::Pair(..) => {
                     llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 0, true));
@@ -408,7 +406,7 @@ impl<'tcx> FnTypeLlvmExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
                 apply(&ArgAttributes::new(), None);
             }
             match arg.mode {
-                PassMode::Ignore(_) => {}
+                PassMode::Ignore => {}
                 PassMode::Direct(ref attrs) |
                 PassMode::Indirect(ref attrs, None) => apply(attrs, Some(arg.layout.llvm_type(cx))),
                 PassMode::Indirect(ref attrs, Some(ref extra_attrs)) => {
@@ -455,7 +453,7 @@ impl<'tcx> FnTypeLlvmExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
                 apply(&ArgAttributes::new(), None);
             }
             match arg.mode {
-                PassMode::Ignore(_) => {}
+                PassMode::Ignore => {}
                 PassMode::Direct(ref attrs) |
                 PassMode::Indirect(ref attrs, None) => apply(attrs, Some(arg.layout.llvm_type(bx))),
                 PassMode::Indirect(ref attrs, Some(ref extra_attrs)) => {
diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index 3069199a21256..0b9519f1c8079 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -3,7 +3,7 @@ use rustc::ty::{self, Ty, TypeFoldable, Instance};
 use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, FnTypeExt};
 use rustc::mir::{self, Place, PlaceBase, Static, StaticKind};
 use rustc::mir::interpret::PanicInfo;
-use rustc_target::abi::call::{ArgType, FnType, PassMode, IgnoreMode};
+use rustc_target::abi::call::{ArgType, FnType, PassMode};
 use rustc_target::spec::abi::Abi;
 use crate::base;
 use crate::MemFlags;
@@ -242,15 +242,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             return;
         }
         let llval = match self.fn_ty.ret.mode {
-            PassMode::Ignore(IgnoreMode::Zst) | PassMode::Indirect(..) => {
+            PassMode::Ignore | PassMode::Indirect(..) => {
                 bx.ret_void();
                 return;
             }
 
-            PassMode::Ignore(IgnoreMode::CVarArgs) => {
-                bug!("C-variadic arguments should never be the return type");
-            }
-
             PassMode::Direct(_) | PassMode::Pair(..) => {
                 let op =
                     self.codegen_consume(&mut bx, &mir::Place::return_place().as_ref());
@@ -502,10 +498,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             return;
         }
 
-        // The "spoofed" `VaListImpl` added to a C-variadic functions signature
-        // should not be included in the `extra_args` calculation.
-        let extra_args_start_idx = sig.inputs().len() - if sig.c_variadic { 1 } else { 0 };
-        let extra_args = &args[extra_args_start_idx..];
+        let extra_args = &args[sig.inputs().len()..];
         let extra_args = extra_args.iter().map(|op_arg| {
             let op_ty = op_arg.ty(self.mir, bx.tcx());
             self.monomorphize(&op_ty)
@@ -691,26 +684,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             (&args[..], None)
         };
 
-        // Useful determining if the current argument is the "spoofed" `VaListImpl`
-        let last_arg_idx = if sig.inputs().is_empty() {
-            None
-        } else {
-            Some(sig.inputs().len() - 1)
-        };
         'make_args: for (i, arg) in first_args.iter().enumerate() {
-            // If this is a C-variadic function the function signature contains
-            // an "spoofed" `VaListImpl`. This argument is ignored, but we need to
-            // populate it with a dummy operand so that the users real arguments
-            // are not overwritten.
-            let i = if sig.c_variadic && last_arg_idx.map(|x| i >= x).unwrap_or(false) {
-                if i + 1 < fn_ty.args.len() {
-                    i + 1
-                } else {
-                    break 'make_args
-                }
-            } else {
-                i
-            };
             let mut op = self.codegen_operand(&mut bx, arg);
 
             if let (0, Some(ty::InstanceDef::Virtual(_, idx))) = (i, def) {
diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs
index c341c0685c6a7..5f8ffaad3d4fd 100644
--- a/src/librustc_codegen_ssa/mir/mod.rs
+++ b/src/librustc_codegen_ssa/mir/mod.rs
@@ -2,7 +2,7 @@ use rustc::ty::{self, Ty, TypeFoldable, UpvarSubsts, Instance};
 use rustc::ty::layout::{TyLayout, HasTyCtxt, FnTypeExt};
 use rustc::mir::{self, Body};
 use rustc::session::config::DebugInfo;
-use rustc_target::abi::call::{FnType, PassMode, IgnoreMode};
+use rustc_target::abi::call::{FnType, PassMode};
 use rustc_target::abi::{Variants, VariantIdx};
 use crate::base;
 use crate::debuginfo::{self, VariableAccess, VariableKind, FunctionDebugContext};
@@ -441,15 +441,6 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         None
     };
 
-    // Store the index of the last argument. This is used to
-    // call va_start on the va_list instead of attempting
-    // to store_fn_arg.
-    let last_arg_idx = if fx.fn_ty.args.is_empty() {
-        None
-    } else {
-        Some(fx.fn_ty.args.len() - 1)
-    };
-
     mir.args_iter().enumerate().map(|(arg_index, local)| {
         let arg_decl = &mir.local_decls[local];
 
@@ -503,6 +494,33 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
             return LocalRef::Place(place);
         }
 
+        if fx.fn_ty.c_variadic && arg_index == fx.fn_ty.args.len() {
+            let arg_ty = fx.monomorphize(&arg_decl.ty);
+
+            let va_list = PlaceRef::alloca(bx, bx.layout_of(arg_ty));
+            bx.set_var_name(va_list.llval, name);
+            bx.va_start(va_list.llval);
+            // FIXME(eddyb) remove `va_list_ref`.
+            *va_list_ref = Some(va_list);
+
+            arg_scope.map(|scope| {
+                let variable_access = VariableAccess::DirectVariable {
+                    alloca: va_list.llval
+                };
+                bx.declare_local(
+                    &fx.debug_context,
+                    arg_decl.name.unwrap_or(kw::Invalid),
+                    va_list.layout.ty,
+                    scope,
+                    variable_access,
+                    VariableKind::ArgumentVariable(arg_index + 1),
+                    DUMMY_SP
+                );
+            });
+
+            return LocalRef::Place(va_list);
+        }
+
         let arg = &fx.fn_ty.args[idx];
         idx += 1;
         if arg.pad.is_some() {
@@ -515,10 +533,9 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
             // of putting everything in allocas just so we can use llvm.dbg.declare.
             let local = |op| LocalRef::Operand(Some(op));
             match arg.mode {
-                PassMode::Ignore(IgnoreMode::Zst) => {
+                PassMode::Ignore => {
                     return local(OperandRef::new_zst(bx, arg.layout));
                 }
-                PassMode::Ignore(IgnoreMode::CVarArgs) => {}
                 PassMode::Direct(_) => {
                     let llarg = bx.get_param(llarg_idx);
                     bx.set_var_name(llarg, &name);
@@ -568,22 +585,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         } else {
             let tmp = PlaceRef::alloca(bx, arg.layout);
             bx.set_var_name(tmp.llval, name);
-            if fx.fn_ty.c_variadic && last_arg_idx.map(|idx| arg_index == idx).unwrap_or(false) {
-                let va_list_did = match tcx.lang_items().va_list() {
-                    Some(did) => did,
-                    None => bug!("`va_list` lang item required for C-variadic functions"),
-                };
-                match arg_decl.ty.kind {
-                    ty::Adt(def, _) if def.did == va_list_did => {
-                        // Call `va_start` on the spoofed `VaListImpl`.
-                        bx.va_start(tmp.llval);
-                        *va_list_ref = Some(tmp);
-                    },
-                    _ => bug!("last argument of variadic function is not a `va_list`")
-                }
-            } else {
-                bx.store_fn_arg(arg, &mut llarg_idx, tmp);
-            }
+            bx.store_fn_arg(arg, &mut llarg_idx, tmp);
             tmp
         };
         let upvar_debuginfo = &mir.__upvar_debuginfo_codegen_only_do_not_use;
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index e4567dc8265d8..150719c1dbc0e 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -944,15 +944,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         let def_id = self.cx.tcx.hir().local_def_id(id);
         let sig = self.cx.tcx.fn_sig(def_id);
         let sig = self.cx.tcx.erase_late_bound_regions(&sig);
-        let inputs = if sig.c_variadic {
-            // Don't include the spoofed `VaListImpl` in the functions list
-            // of inputs.
-            &sig.inputs()[..sig.inputs().len() - 1]
-        } else {
-            &sig.inputs()[..]
-        };
 
-        for (input_ty, input_hir) in inputs.iter().zip(&decl.inputs) {
+        for (input_ty, input_hir) in sig.inputs().iter().zip(&decl.inputs) {
             self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty);
         }
 
diff --git a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs
index 99661b1f7370a..edf9549b626aa 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs
@@ -9,8 +9,10 @@
 
 use crate::borrow_check::nll::universal_regions::UniversalRegions;
 use rustc::infer::LateBoundRegionConversionTime;
+use rustc::middle::lang_items;
 use rustc::mir::*;
-use rustc::ty::Ty;
+use rustc::ty::{self, Ty};
+use rustc::ty::subst::Subst;
 
 use rustc_data_structures::indexed_vec::Idx;
 use syntax_pos::Span;
@@ -63,8 +65,22 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             }
         };
 
+        // C-variadic fns also have a `VaList` input that's not listed in the signature
+        // (as it's created inside the body itself, not passed in from outside).
+        let maybe_va_list = if universal_regions.c_variadic {
+            let va_list_did =
+                self.tcx().require_lang_item(lang_items::VaListTypeLangItem, Some(body.span));
+            let region = self.tcx().mk_region(ty::ReVar(universal_regions.fr_fn_body));
+
+            Some(self.tcx().type_of(va_list_did).subst(self.tcx(), &[region.into()]))
+        } else {
+            None
+        };
+
         // Equate expected input tys with those in the MIR.
-        for (&normalized_input_ty, argument_index) in normalized_input_tys.iter().zip(0..) {
+        for (normalized_input_ty, argument_index) in
+            normalized_input_tys.iter().copied().chain(maybe_va_list).zip(0..)
+        {
             // In MIR, argument N is stored in local N+1.
             let local = Local::new(argument_index + 1);
 
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index e3e509799c936..08f10b0612d00 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -1726,17 +1726,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         from_hir_call: bool,
     ) {
         debug!("check_call_inputs({:?}, {:?})", sig, args);
-        // Do not count the `VaListImpl` argument as a "true" argument to
-        // a C-variadic function.
-        let inputs = if sig.c_variadic {
-            &sig.inputs()[..sig.inputs().len() - 1]
-        } else {
-            &sig.inputs()[..]
-        };
-        if args.len() < inputs.len() || (args.len() > inputs.len() && !sig.c_variadic) {
+        if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.c_variadic) {
             span_mirbug!(self, term, "call to {:?} with wrong # of args", sig);
         }
-        for (n, (fn_arg, op_arg)) in inputs.iter().zip(args).enumerate() {
+        for (n, (fn_arg, op_arg)) in sig.inputs().iter().zip(args).enumerate() {
             let op_arg_ty = op_arg.ty(body, self.tcx());
             let category = if from_hir_call {
                 ConstraintCategory::CallArgument
diff --git a/src/librustc_mir/borrow_check/nll/universal_regions.rs b/src/librustc_mir/borrow_check/nll/universal_regions.rs
index b5af97a2217e8..c74f58dbf46ec 100644
--- a/src/librustc_mir/borrow_check/nll/universal_regions.rs
+++ b/src/librustc_mir/borrow_check/nll/universal_regions.rs
@@ -72,6 +72,8 @@ pub struct UniversalRegions<'tcx> {
     pub unnormalized_input_tys: &'tcx [Ty<'tcx>],
 
     pub yield_ty: Option<Ty<'tcx>>,
+
+    pub c_variadic: bool,
 }
 
 /// The "defining type" for this MIR. The key feature of the "defining
@@ -451,6 +453,13 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
             _ => None,
         };
 
+        let c_variadic = match defining_ty {
+            DefiningTy::FnDef(def_id, _) => {
+                self.infcx.tcx.fn_sig(def_id).c_variadic()
+            }
+            _ => false,
+        };
+
         UniversalRegions {
             indices,
             fr_static,
@@ -462,6 +471,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
             unnormalized_output_ty,
             unnormalized_input_tys,
             yield_ty: yield_ty,
+            c_variadic,
         }
     }
 
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index f1e045302eced..17932ae855767 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -7,9 +7,11 @@ use crate::util as mir_util;
 use rustc::hir;
 use rustc::hir::Node;
 use rustc::hir::def_id::DefId;
+use rustc::middle::lang_items;
 use rustc::middle::region;
 use rustc::mir::*;
 use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::subst::Subst;
 use rustc::util::nodemap::HirIdMap;
 use rustc_target::spec::PanicStrategy;
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
@@ -102,9 +104,7 @@ pub fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> Body<'_> {
                         let opt_ty_info;
                         let self_arg;
                         if let Some(ref fn_decl) = tcx.hir().fn_decl_by_hir_id(owner_id) {
-                            let ty_hir_id = fn_decl.inputs[index].hir_id;
-                            let ty_span = tcx.hir().span(ty_hir_id);
-                            opt_ty_info = Some(ty_span);
+                            opt_ty_info = fn_decl.inputs.get(index).map(|ty| ty.span);
                             self_arg = if index == 0 && fn_decl.implicit_self.has_implicit_self() {
                                 match fn_decl.implicit_self {
                                     hir::ImplicitSelfKind::Imm => Some(ImplicitSelfKind::Imm),
@@ -121,7 +121,24 @@ pub fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> Body<'_> {
                             self_arg = None;
                         }
 
-                        ArgInfo(fn_sig.inputs()[index], opt_ty_info, Some(&arg), self_arg)
+                        // C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
+                        // (as it's created inside the body itself, not passed in from outside).
+                        let ty = if fn_sig.c_variadic && index == fn_sig.inputs().len() {
+                            let va_list_did = tcx.require_lang_item(
+                                lang_items::VaListTypeLangItem,
+                                Some(arg.span),
+                            );
+                            let region = tcx.mk_region(ty::ReScope(region::Scope {
+                                id: body.value.hir_id.local_id,
+                                data: region::ScopeData::CallSite
+                            }));
+
+                            tcx.type_of(va_list_did).subst(tcx, &[region.into()])
+                        } else {
+                            fn_sig.inputs()[index]
+                        };
+
+                        ArgInfo(ty, opt_ty_info, Some(&arg), self_arg)
                     });
 
             let arguments = implicit_argument.into_iter().chain(explicit_arguments);
diff --git a/src/librustc_target/abi/call/mod.rs b/src/librustc_target/abi/call/mod.rs
index fbbd120f934be..bc21113527ecf 100644
--- a/src/librustc_target/abi/call/mod.rs
+++ b/src/librustc_target/abi/call/mod.rs
@@ -23,18 +23,10 @@ mod x86_64;
 mod x86_win64;
 mod wasm32;
 
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
-pub enum IgnoreMode {
-    /// C-variadic arguments.
-    CVarArgs,
-    /// A zero-sized type.
-    Zst,
-}
-
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
 pub enum PassMode {
-    /// Ignore the argument (useful for empty structs and C-variadic args).
-    Ignore(IgnoreMode),
+    /// Ignore the argument.
+    Ignore,
     /// Pass the argument directly.
     Direct(ArgAttributes),
     /// Pass a pair's elements directly in two arguments.
@@ -490,7 +482,7 @@ impl<'a, Ty> ArgType<'a, Ty> {
 
     pub fn is_ignore(&self) -> bool {
         match self.mode {
-            PassMode::Ignore(_) => true,
+            PassMode::Ignore => true,
             _ => false
         }
     }
diff --git a/src/librustc_target/abi/call/x86.rs b/src/librustc_target/abi/call/x86.rs
index 6ca3ce88bd6eb..2e809571ab18b 100644
--- a/src/librustc_target/abi/call/x86.rs
+++ b/src/librustc_target/abi/call/x86.rs
@@ -88,7 +88,7 @@ pub fn compute_abi_info<'a, Ty, C>(cx: &C, fty: &mut FnType<'a, Ty>, flavor: Fla
 
         for arg in &mut fty.args {
             let attrs = match arg.mode {
-                PassMode::Ignore(_) |
+                PassMode::Ignore |
                 PassMode::Indirect(_, None) => continue,
                 PassMode::Direct(ref mut attrs) => attrs,
                 PassMode::Pair(..) |
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 5021277e04a2b..fdd40ce08f551 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -2151,18 +2151,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 // handled specially and will not descend into this routine.
                 self.ty_infer(None, ast_ty.span)
             }
-            hir::TyKind::CVarArgs => {
-                let va_list_did = match tcx.lang_items().va_list() {
-                    Some(did) => did,
-                    None => span_bug!(ast_ty.span,
-                                      "`va_list` lang item required for variadics"),
-                };
-                // FIXME(eddyb) compute this in the body and don't let it reach the signature.
-                // HACK(eddyb) the `123` anon index is only temporary, to keep tests passing.
-                // Ideally this would use `ReScope` or similar.
-                let region = tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BrAnon(123)));
-                tcx.type_of(va_list_did).subst(tcx, &[region.into()])
-            }
             hir::TyKind::Err => {
                 tcx.types.err
             }
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index 4d8ec6fb0b83d..9e1fbc067d2e3 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -406,27 +406,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             .0;
         let fn_sig = self.normalize_associated_types_in(call_expr.span, &fn_sig);
 
-        let inputs = if fn_sig.c_variadic {
-            if fn_sig.inputs().len() > 1 {
-                &fn_sig.inputs()[..fn_sig.inputs().len() - 1]
-            } else {
-                span_bug!(call_expr.span,
-                          "C-variadic functions are only valid with one or more fixed arguments");
-            }
-        } else {
-            &fn_sig.inputs()[..]
-        };
         // Call the generic checker.
         let expected_arg_tys = self.expected_inputs_for_expected_output(
             call_expr.span,
             expected,
             fn_sig.output(),
-            inputs,
+            fn_sig.inputs(),
         );
         self.check_argument_types(
             call_expr.span,
             call_expr,
-            inputs,
+            fn_sig.inputs(),
             &expected_arg_tys[..],
             arg_exprs,
             fn_sig.c_variadic,
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 9f2c991fdd236..a7832b8c2cf17 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1132,8 +1132,29 @@ fn check_fn<'a, 'tcx>(
     let outer_hir_id = fcx.tcx.hir().as_local_hir_id(outer_def_id).unwrap();
     GatherLocalsVisitor { fcx: &fcx, parent_id: outer_hir_id, }.visit_body(body);
 
+    // C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
+    // (as it's created inside the body itself, not passed in from outside).
+    let maybe_va_list = if fn_sig.c_variadic {
+        let va_list_did = fcx.tcx.require_lang_item(
+            lang_items::VaListTypeLangItem,
+            Some(body.params.last().unwrap().span),
+        );
+        let region = fcx.tcx.mk_region(ty::ReScope(region::Scope {
+            id: body.value.hir_id.local_id,
+            data: region::ScopeData::CallSite
+        }));
+
+        Some(fcx.tcx.type_of(va_list_did).subst(fcx.tcx, &[region.into()]))
+    } else {
+        None
+    };
+
     // Add formal parameters.
-    for (param_ty, param) in fn_sig.inputs().iter().zip(&body.params) {
+    for (param_ty, param) in
+        fn_sig.inputs().iter().copied()
+            .chain(maybe_va_list)
+            .zip(&body.params)
+    {
         // Check the pattern.
         fcx.check_pat_top(&param.pat, param_ty, None);
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 24d017147e4c6..b530851b80de7 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2032,6 +2032,7 @@ impl Clean<Item> for doctree::Function<'_> {
 pub struct FnDecl {
     pub inputs: Arguments,
     pub output: FunctionRetTy,
+    pub c_variadic: bool,
     pub attrs: Attributes,
 }
 
@@ -2110,6 +2111,7 @@ impl<'a, A: Copy> Clean<FnDecl> for (&'a hir::FnDecl, A)
         FnDecl {
             inputs: (&self.0.inputs[..], self.1).clean(cx),
             output: self.0.output.clean(cx),
+            c_variadic: self.0.c_variadic,
             attrs: Attributes::default(),
         }
     }
@@ -2127,6 +2129,7 @@ impl<'tcx> Clean<FnDecl> for (DefId, ty::PolyFnSig<'tcx>) {
         FnDecl {
             output: Return(sig.skip_binder().output().clean(cx)),
             attrs: Attributes::default(),
+            c_variadic: sig.skip_binder().c_variadic,
             inputs: Arguments {
                 values: sig.skip_binder().inputs().iter().map(|t| {
                     Argument {
@@ -2545,7 +2548,6 @@ pub enum Type {
     Slice(Box<Type>),
     Array(Box<Type>, String),
     Never,
-    CVarArgs,
     RawPointer(Mutability, Box<Type>),
     BorrowedRef {
         lifetime: Option<Lifetime>,
@@ -2583,7 +2585,6 @@ pub enum PrimitiveType {
     Reference,
     Fn,
     Never,
-    CVarArgs,
 }
 
 #[derive(Clone, Copy, Debug)]
@@ -2787,7 +2788,6 @@ impl PrimitiveType {
             Reference => "reference",
             Fn => "fn",
             Never => "never",
-            CVarArgs => "...",
         }
     }
 
@@ -3032,7 +3032,6 @@ impl Clean<Type> for hir::Ty {
             TyKind::BareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
             TyKind::Infer | TyKind::Err => Infer,
             TyKind::Typeof(..) => panic!("unimplemented type {:?}", self.kind),
-            TyKind::CVarArgs => CVarArgs,
         }
     }
 }
@@ -3980,7 +3979,6 @@ fn build_deref_target_impls(cx: &DocContext<'_>,
             Reference => None,
             Fn => None,
             Never => None,
-            CVarArgs => tcx.lang_items().va_list(),
         };
         if let Some(did) = did {
             if !did.is_local() {
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index fafd43cb60b69..4cde868201eef 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -657,7 +657,6 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) ->
             primitive_link(f, PrimitiveType::Array, &format!("; {}]", n))
         }
         clean::Never => primitive_link(f, PrimitiveType::Never, "!"),
-        clean::CVarArgs => primitive_link(f, PrimitiveType::CVarArgs, "..."),
         clean::RawPointer(m, ref t) => {
             let m = match m {
                 clean::Immutable => "const",
@@ -903,12 +902,15 @@ impl clean::BareFunctionDecl {
 impl clean::FnDecl {
     crate fn print(&self) -> impl fmt::Display + '_ {
         display_fn(move |f| {
+        let ellipsis = if self.c_variadic { ", ..." } else { "" };
             if f.alternate() {
                 write!(f,
-                    "({args:#}){arrow:#}", args = self.inputs.print(), arrow = self.output.print())
+                    "({args:#}{ellipsis}){arrow:#}",
+                    args = self.inputs.print(), ellipsis = ellipsis, arrow = self.output.print())
             } else {
                 write!(f,
-                    "({args}){arrow}", args = self.inputs.print(), arrow = self.output.print())
+                    "({args}{ellipsis}){arrow}",
+                    args = self.inputs.print(), ellipsis = ellipsis, arrow = self.output.print())
             }
         })
     }
@@ -975,7 +977,12 @@ impl Function<'_> {
                 }
             }
 
-            let args_plain = format!("({})", args_plain);
+            let mut args_plain = format!("({})", args_plain);
+
+            if decl.c_variadic {
+                args.push_str(",<br> ...");
+                args_plain.push_str(", ...");
+            }
 
             let output = if let hir::IsAsync::Async = asyncness {
                 Cow::Owned(decl.sugared_async_return_type())
diff --git a/src/test/rustdoc/variadic.rs b/src/test/rustdoc/variadic.rs
index 5af2aea21fcac..bd8f1775b3d04 100644
--- a/src/test/rustdoc/variadic.rs
+++ b/src/test/rustdoc/variadic.rs
@@ -1,4 +1,4 @@
 extern "C" {
-    // @has variadic/fn.foo.html //pre 'pub unsafe extern "C" fn foo(x: i32, _: ...)'
+    // @has variadic/fn.foo.html //pre 'pub unsafe extern "C" fn foo(x: i32, ...)'
     pub fn foo(x: i32, ...);
 }
diff --git a/src/test/ui/c-variadic/variadic-ffi-1.stderr b/src/test/ui/c-variadic/variadic-ffi-1.stderr
index 695eba2a7ee40..73f72a177bcaa 100644
--- a/src/test/ui/c-variadic/variadic-ffi-1.stderr
+++ b/src/test/ui/c-variadic/variadic-ffi-1.stderr
@@ -29,7 +29,7 @@ LL |         let x: unsafe extern "C" fn(f: isize, x: u8) = foo;
    |                                                        ^^^ expected non-variadic fn, found variadic function
    |
    = note: expected type `unsafe extern "C" fn(isize, u8)`
-              found type `for<'r> unsafe extern "C" fn(isize, u8, std::ffi::VaListImpl<'r>, ...) {foo}`
+              found type `unsafe extern "C" fn(isize, u8, ...) {foo}`
 
 error[E0308]: mismatched types
   --> $DIR/variadic-ffi-1.rs:20:54
@@ -37,7 +37,7 @@ error[E0308]: mismatched types
 LL |         let y: extern "C" fn(f: isize, x: u8, ...) = bar;
    |                                                      ^^^ expected variadic fn, found non-variadic function
    |
-   = note: expected type `for<'r> extern "C" fn(isize, u8, std::ffi::VaListImpl<'r>, ...)`
+   = note: expected type `extern "C" fn(isize, u8, ...)`
               found type `extern "C" fn(isize, u8) {bar}`
 
 error[E0617]: can't pass `f32` to variadic function
diff --git a/src/test/ui/c-variadic/variadic-ffi-4.rs b/src/test/ui/c-variadic/variadic-ffi-4.rs
index 4a50d352a5b20..a4d658cef1630 100644
--- a/src/test/ui/c-variadic/variadic-ffi-4.rs
+++ b/src/test/ui/c-variadic/variadic-ffi-4.rs
@@ -5,11 +5,11 @@
 use core::ffi::{VaList, VaListImpl};
 
 pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> {
-    ap //~ ERROR: explicit lifetime required
+    ap //~ ERROR: mismatched types
 }
 
 pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaListImpl<'static> {
-    ap //~ ERROR: explicit lifetime required
+    ap //~ ERROR: mismatched types
 }
 
 pub unsafe extern "C" fn no_escape2(_: usize, ap: ...) {
@@ -18,18 +18,15 @@ pub unsafe extern "C" fn no_escape2(_: usize, ap: ...) {
 
 pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
     *ap0 = ap1; //~ ERROR: mismatched types
-    //~^ ERROR: mismatched types
 }
 
 pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) {
     ap0 = &mut ap1;
     //~^ ERROR: a value of type `core::ffi::VaListImpl<'_>` is borrowed for too long
-    //~^^ ERROR: mismatched types
-    //~^^^ ERROR: mismatched types
-    //~^^^^ ERROR: cannot infer an appropriate lifetime
+    //~| ERROR: mismatched types
+    //~| ERROR: cannot infer an appropriate lifetime
 }
 
 pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
     *ap0 = ap1.clone(); //~ ERROR: mismatched types
-    //~^ ERROR: mismatched types
 }
diff --git a/src/test/ui/c-variadic/variadic-ffi-4.stderr b/src/test/ui/c-variadic/variadic-ffi-4.stderr
index 3b7eb26c0732e..b986d0c243506 100644
--- a/src/test/ui/c-variadic/variadic-ffi-4.stderr
+++ b/src/test/ui/c-variadic/variadic-ffi-4.stderr
@@ -1,18 +1,42 @@
-error[E0621]: explicit lifetime required in the type of `ap`
+error[E0308]: mismatched types
   --> $DIR/variadic-ffi-4.rs:8:5
    |
-LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> {
-   |                                                       --- help: add explicit lifetime `'f` to the type of `ap`: `core::ffi::VaListImpl<'f>`
 LL |     ap
-   |     ^^ lifetime `'f` required
+   |     ^^ lifetime mismatch
+   |
+   = note: expected type `core::ffi::VaListImpl<'f>`
+              found type `core::ffi::VaListImpl<'_>`
+note: the scope of call-site for function at 7:78...
+  --> $DIR/variadic-ffi-4.rs:7:78
+   |
+LL |   pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> {
+   |  ______________________________________________________________________________^
+LL | |     ap
+LL | | }
+   | |_^
+note: ...does not necessarily outlive the lifetime 'f as defined on the function body at 7:37
+  --> $DIR/variadic-ffi-4.rs:7:37
+   |
+LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> {
+   |                                     ^^
 
-error[E0621]: explicit lifetime required in the type of `ap`
+error[E0308]: mismatched types
   --> $DIR/variadic-ffi-4.rs:12:5
    |
-LL | pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaListImpl<'static> {
-   |                                                   --- help: add explicit lifetime `'static` to the type of `ap`: `core::ffi::VaListImpl<'static>`
 LL |     ap
-   |     ^^ lifetime `'static` required
+   |     ^^ lifetime mismatch
+   |
+   = note: expected type `core::ffi::VaListImpl<'static>`
+              found type `core::ffi::VaListImpl<'_>`
+note: the scope of call-site for function at 11:79...
+  --> $DIR/variadic-ffi-4.rs:11:79
+   |
+LL |   pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaListImpl<'static> {
+   |  _______________________________________________________________________________^
+LL | |     ap
+LL | | }
+   | |_^
+   = note: ...does not necessarily outlive the static lifetime
 
 error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
   --> $DIR/variadic-ffi-4.rs:16:33
@@ -47,12 +71,12 @@ LL |     *ap0 = ap1;
    |
    = note: expected type `core::ffi::VaListImpl<'_>`
               found type `core::ffi::VaListImpl<'_>`
-note: the anonymous lifetime #124 defined on the function body at 19:1...
-  --> $DIR/variadic-ffi-4.rs:19:1
+note: the scope of call-site for function at 19:87...
+  --> $DIR/variadic-ffi-4.rs:19:87
    |
-LL | / pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
+LL |   pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
+   |  _______________________________________________________________________________________^
 LL | |     *ap0 = ap1;
-LL | |
 LL | | }
    | |_^
 note: ...does not necessarily outlive the anonymous lifetime #2 defined on the function body at 19:1
@@ -60,216 +84,129 @@ note: ...does not necessarily outlive the anonymous lifetime #2 defined on the f
    |
 LL | / pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
 LL | |     *ap0 = ap1;
-LL | |
-LL | | }
-   | |_^
-
-error[E0308]: mismatched types
-  --> $DIR/variadic-ffi-4.rs:20:12
-   |
-LL |     *ap0 = ap1;
-   |            ^^^ lifetime mismatch
-   |
-   = note: expected type `core::ffi::VaListImpl<'_>`
-              found type `core::ffi::VaListImpl<'_>`
-note: the anonymous lifetime #2 defined on the function body at 19:1...
-  --> $DIR/variadic-ffi-4.rs:19:1
-   |
-LL | / pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
-LL | |     *ap0 = ap1;
-LL | |
-LL | | }
-   | |_^
-note: ...does not necessarily outlive the anonymous lifetime #124 defined on the function body at 19:1
-  --> $DIR/variadic-ffi-4.rs:19:1
-   |
-LL | / pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
-LL | |     *ap0 = ap1;
-LL | |
 LL | | }
    | |_^
 
 error[E0490]: a value of type `core::ffi::VaListImpl<'_>` is borrowed for too long
-  --> $DIR/variadic-ffi-4.rs:25:11
+  --> $DIR/variadic-ffi-4.rs:24:11
    |
 LL |     ap0 = &mut ap1;
    |           ^^^^^^^^
    |
-note: the type is valid for the anonymous lifetime #1 defined on the function body at 24:1
-  --> $DIR/variadic-ffi-4.rs:24:1
-   |
-LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) {
-LL | |     ap0 = &mut ap1;
-LL | |
-LL | |
-LL | |
-LL | |
-LL | | }
-   | |_^
-note: but the borrow lasts for the anonymous lifetime #124 defined on the function body at 24:1
-  --> $DIR/variadic-ffi-4.rs:24:1
-   |
-LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) {
-LL | |     ap0 = &mut ap1;
-LL | |
-LL | |
-LL | |
-LL | |
-LL | | }
-   | |_^
-
-error[E0308]: mismatched types
-  --> $DIR/variadic-ffi-4.rs:25:11
-   |
-LL |     ap0 = &mut ap1;
-   |           ^^^^^^^^ lifetime mismatch
-   |
-   = note: expected type `&mut core::ffi::VaListImpl<'_>`
-              found type `&mut core::ffi::VaListImpl<'_>`
-note: the anonymous lifetime #124 defined on the function body at 24:1...
-  --> $DIR/variadic-ffi-4.rs:24:1
+note: the type is valid for the anonymous lifetime #1 defined on the function body at 23:1
+  --> $DIR/variadic-ffi-4.rs:23:1
    |
 LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) {
 LL | |     ap0 = &mut ap1;
 LL | |
 LL | |
 LL | |
-LL | |
 LL | | }
    | |_^
-note: ...does not necessarily outlive the anonymous lifetime #2 defined on the function body at 24:1
-  --> $DIR/variadic-ffi-4.rs:24:1
+note: but the borrow lasts for the scope of call-site for function at 23:83
+  --> $DIR/variadic-ffi-4.rs:23:83
    |
-LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) {
+LL |   pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) {
+   |  ___________________________________________________________________________________^
 LL | |     ap0 = &mut ap1;
 LL | |
 LL | |
 LL | |
-LL | |
 LL | | }
    | |_^
 
 error[E0308]: mismatched types
-  --> $DIR/variadic-ffi-4.rs:25:11
+  --> $DIR/variadic-ffi-4.rs:24:11
    |
 LL |     ap0 = &mut ap1;
    |           ^^^^^^^^ lifetime mismatch
    |
    = note: expected type `&mut core::ffi::VaListImpl<'_>`
               found type `&mut core::ffi::VaListImpl<'_>`
-note: the anonymous lifetime #2 defined on the function body at 24:1...
-  --> $DIR/variadic-ffi-4.rs:24:1
+note: the scope of call-site for function at 23:83...
+  --> $DIR/variadic-ffi-4.rs:23:83
    |
-LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) {
+LL |   pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) {
+   |  ___________________________________________________________________________________^
 LL | |     ap0 = &mut ap1;
 LL | |
 LL | |
 LL | |
-LL | |
 LL | | }
    | |_^
-note: ...does not necessarily outlive the anonymous lifetime #124 defined on the function body at 24:1
-  --> $DIR/variadic-ffi-4.rs:24:1
+note: ...does not necessarily outlive the anonymous lifetime #2 defined on the function body at 23:1
+  --> $DIR/variadic-ffi-4.rs:23:1
    |
 LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) {
 LL | |     ap0 = &mut ap1;
 LL | |
 LL | |
 LL | |
-LL | |
 LL | | }
    | |_^
 
 error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
-  --> $DIR/variadic-ffi-4.rs:25:11
+  --> $DIR/variadic-ffi-4.rs:24:11
    |
 LL |     ap0 = &mut ap1;
    |           ^^^^^^^^
    |
-note: first, the lifetime cannot outlive the anonymous lifetime #124 defined on the function body at 24:1...
-  --> $DIR/variadic-ffi-4.rs:24:1
+note: first, the lifetime cannot outlive the scope of call-site for function at 23:83...
+  --> $DIR/variadic-ffi-4.rs:23:83
    |
-LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) {
+LL |   pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) {
+   |  ___________________________________________________________________________________^
 LL | |     ap0 = &mut ap1;
 LL | |
 LL | |
 LL | |
-LL | |
 LL | | }
    | |_^
 note: ...so that the type `core::ffi::VaListImpl<'_>` is not borrowed for too long
-  --> $DIR/variadic-ffi-4.rs:25:11
+  --> $DIR/variadic-ffi-4.rs:24:11
    |
 LL |     ap0 = &mut ap1;
    |           ^^^^^^^^
-note: but, the lifetime must be valid for the anonymous lifetime #1 defined on the function body at 24:1...
-  --> $DIR/variadic-ffi-4.rs:24:1
+note: but, the lifetime must be valid for the anonymous lifetime #1 defined on the function body at 23:1...
+  --> $DIR/variadic-ffi-4.rs:23:1
    |
 LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) {
 LL | |     ap0 = &mut ap1;
 LL | |
 LL | |
 LL | |
-LL | |
 LL | | }
    | |_^
 note: ...so that reference does not outlive borrowed content
-  --> $DIR/variadic-ffi-4.rs:25:11
+  --> $DIR/variadic-ffi-4.rs:24:11
    |
 LL |     ap0 = &mut ap1;
    |           ^^^^^^^^
 
 error[E0308]: mismatched types
-  --> $DIR/variadic-ffi-4.rs:33:12
+  --> $DIR/variadic-ffi-4.rs:31:12
    |
 LL |     *ap0 = ap1.clone();
    |            ^^^^^^^^^^^ lifetime mismatch
    |
    = note: expected type `core::ffi::VaListImpl<'_>`
               found type `core::ffi::VaListImpl<'_>`
-note: the anonymous lifetime #124 defined on the function body at 32:1...
-  --> $DIR/variadic-ffi-4.rs:32:1
+note: the scope of call-site for function at 30:87...
+  --> $DIR/variadic-ffi-4.rs:30:87
    |
-LL | / pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
+LL |   pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
+   |  _______________________________________________________________________________________^
 LL | |     *ap0 = ap1.clone();
-LL | |
 LL | | }
    | |_^
-note: ...does not necessarily outlive the anonymous lifetime #2 defined on the function body at 32:1
-  --> $DIR/variadic-ffi-4.rs:32:1
+note: ...does not necessarily outlive the anonymous lifetime #2 defined on the function body at 30:1
+  --> $DIR/variadic-ffi-4.rs:30:1
    |
 LL | / pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
 LL | |     *ap0 = ap1.clone();
-LL | |
-LL | | }
-   | |_^
-
-error[E0308]: mismatched types
-  --> $DIR/variadic-ffi-4.rs:33:12
-   |
-LL |     *ap0 = ap1.clone();
-   |            ^^^^^^^^^^^ lifetime mismatch
-   |
-   = note: expected type `core::ffi::VaListImpl<'_>`
-              found type `core::ffi::VaListImpl<'_>`
-note: the anonymous lifetime #2 defined on the function body at 32:1...
-  --> $DIR/variadic-ffi-4.rs:32:1
-   |
-LL | / pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
-LL | |     *ap0 = ap1.clone();
-LL | |
-LL | | }
-   | |_^
-note: ...does not necessarily outlive the anonymous lifetime #124 defined on the function body at 32:1
-  --> $DIR/variadic-ffi-4.rs:32:1
-   |
-LL | / pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
-LL | |     *ap0 = ap1.clone();
-LL | |
 LL | | }
    | |_^
 
-error: aborting due to 11 previous errors
+error: aborting due to 8 previous errors
 
-Some errors have detailed explanations: E0308, E0621.
-For more information about an error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/error-codes/E0617.rs b/src/test/ui/error-codes/E0617.rs
index 439c3db576864..c832e09ac1118 100644
--- a/src/test/ui/error-codes/E0617.rs
+++ b/src/test/ui/error-codes/E0617.rs
@@ -1,5 +1,3 @@
-// ignore-tidy-linelength
-
 extern {
     fn printf(c: *const i8, ...);
 }
@@ -22,7 +20,7 @@ fn main() {
         //~^ ERROR can't pass `u16` to variadic function
         //~| HELP cast the value to `c_uint`
         printf(::std::ptr::null(), printf);
-        //~^ ERROR can't pass `for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaListImpl<'r>, ...) {printf}` to variadic function
-        //~| HELP cast the value to `for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaListImpl<'r>, ...)`
+        //~^ ERROR can't pass `unsafe extern "C" fn(*const i8, ...) {printf}` to variadic function
+        //~| HELP cast the value to `unsafe extern "C" fn(*const i8, ...)`
     }
 }
diff --git a/src/test/ui/error-codes/E0617.stderr b/src/test/ui/error-codes/E0617.stderr
index d866320bbcdf7..7c4df099d0dd1 100644
--- a/src/test/ui/error-codes/E0617.stderr
+++ b/src/test/ui/error-codes/E0617.stderr
@@ -1,42 +1,42 @@
 error[E0617]: can't pass `f32` to variadic function
-  --> $DIR/E0617.rs:9:36
+  --> $DIR/E0617.rs:7:36
    |
 LL |         printf(::std::ptr::null(), 0f32);
    |                                    ^^^^ help: cast the value to `c_double`: `0f32 as c_double`
 
 error[E0617]: can't pass `i8` to variadic function
-  --> $DIR/E0617.rs:12:36
+  --> $DIR/E0617.rs:10:36
    |
 LL |         printf(::std::ptr::null(), 0i8);
    |                                    ^^^ help: cast the value to `c_int`: `0i8 as c_int`
 
 error[E0617]: can't pass `i16` to variadic function
-  --> $DIR/E0617.rs:15:36
+  --> $DIR/E0617.rs:13:36
    |
 LL |         printf(::std::ptr::null(), 0i16);
    |                                    ^^^^ help: cast the value to `c_int`: `0i16 as c_int`
 
 error[E0617]: can't pass `u8` to variadic function
-  --> $DIR/E0617.rs:18:36
+  --> $DIR/E0617.rs:16:36
    |
 LL |         printf(::std::ptr::null(), 0u8);
    |                                    ^^^ help: cast the value to `c_uint`: `0u8 as c_uint`
 
 error[E0617]: can't pass `u16` to variadic function
-  --> $DIR/E0617.rs:21:36
+  --> $DIR/E0617.rs:19:36
    |
 LL |         printf(::std::ptr::null(), 0u16);
    |                                    ^^^^ help: cast the value to `c_uint`: `0u16 as c_uint`
 
-error[E0617]: can't pass `for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaListImpl<'r>, ...) {printf}` to variadic function
-  --> $DIR/E0617.rs:24:36
+error[E0617]: can't pass `unsafe extern "C" fn(*const i8, ...) {printf}` to variadic function
+  --> $DIR/E0617.rs:22:36
    |
 LL |         printf(::std::ptr::null(), printf);
    |                                    ^^^^^^
-help: cast the value to `for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaListImpl<'r>, ...)`
+help: cast the value to `unsafe extern "C" fn(*const i8, ...)`
    |
-LL |         printf(::std::ptr::null(), printf as for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaListImpl<'r>, ...));
-   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         printf(::std::ptr::null(), printf as unsafe extern "C" fn(*const i8, ...));
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/symbol-names/impl1.legacy.stderr b/src/test/ui/symbol-names/impl1.legacy.stderr
index c1d22a919d900..a3d966bb0b035 100644
--- a/src/test/ui/symbol-names/impl1.legacy.stderr
+++ b/src/test/ui/symbol-names/impl1.legacy.stderr
@@ -46,26 +46,26 @@ error: def-path(bar::<impl foo::Foo>::baz)
 LL |         #[rustc_def_path]
    |         ^^^^^^^^^^^^^^^^^
 
-error: symbol-name(_ZN198_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$RP$$u2b$impl1..AutoTrait$u3b$$u20$_$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method17h6f205aef6a8ccc7bE)
-  --> $DIR/impl1.rs:63:13
+error: symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$_$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method17h059bf53000885489E)
+  --> $DIR/impl1.rs:61:13
    |
 LL |             #[rustc_symbol_name]
    |             ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method::h6f205aef6a8ccc7b)
-  --> $DIR/impl1.rs:63:13
+error: demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method::h059bf53000885489)
+  --> $DIR/impl1.rs:61:13
    |
 LL |             #[rustc_symbol_name]
    |             ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling-alt(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method)
-  --> $DIR/impl1.rs:63:13
+error: demangling-alt(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method)
+  --> $DIR/impl1.rs:61:13
    |
 LL |             #[rustc_symbol_name]
    |             ^^^^^^^^^^^^^^^^^^^^
 
-error: def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8)> + AutoTrait; _] as main::{{closure}}#1::Bar>::method)
-  --> $DIR/impl1.rs:70:13
+error: def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8, ...)> + AutoTrait; _] as main::{{closure}}#1::Bar>::method)
+  --> $DIR/impl1.rs:68:13
    |
 LL |             #[rustc_def_path]
    |             ^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/symbol-names/impl1.rs b/src/test/ui/symbol-names/impl1.rs
index 137b72dcd9c44..add0d10ea6cb0 100644
--- a/src/test/ui/symbol-names/impl1.rs
+++ b/src/test/ui/symbol-names/impl1.rs
@@ -57,19 +57,17 @@ fn main() {
         }
 
         // Test type mangling, by putting them in an `impl` header.
-        // FIXME(eddyb) test C varargs when `core::ffi::VaListImpl` stops leaking into the signature
-        // (which is a problem because `core` has an unpredictable hash) - see also #44930.
-        impl Bar for [&'_ (dyn Foo<Assoc = extern fn(&u8, /*...*/)> + AutoTrait); 3] {
+        impl Bar for [&'_ (dyn Foo<Assoc = extern fn(&u8, ...)> + AutoTrait); 3] {
             #[rustc_symbol_name]
-            //[legacy]~^ ERROR symbol-name(_ZN198_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$RP$$u2b$impl1..AutoTrait$u3b$$u20$_$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method
-            //[legacy]~| ERROR demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method
-            //[legacy]~| ERROR demangling-alt(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method)
-             //[v0]~^^^^ ERROR symbol-name(_RNvXNCNvCs4fqI2P2rA04_5impl14mains_0ARDNtB6_3Foop5AssocFG_KCRL0_hEuNtB6_9AutoTraitEL_j3_NtB2_3Bar6method)
-                //[v0]~| ERROR demangling(<[&dyn impl1[317d481089b8c8fe]::Foo<Assoc = for<'a> extern "C" fn(&'a u8)> + impl1[317d481089b8c8fe]::AutoTrait; 3: usize] as impl1[317d481089b8c8fe]::main::{closure#1}::Bar>::method)
-                //[v0]~| ERROR demangling-alt(<[&dyn impl1::Foo<Assoc = for<'a> extern "C" fn(&'a u8)> + impl1::AutoTrait; 3] as impl1::main::{closure#1}::Bar>::method)
+            //[legacy]~^ ERROR symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$_$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method
+            //[legacy]~| ERROR demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method
+            //[legacy]~| ERROR demangling-alt(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method)
+             //[v0]~^^^^ ERROR symbol-name(_RNvXNCNvCs4fqI2P2rA04_5impl14mains_0ARDNtB6_3Foop5AssocFG_KCRL0_hvEuNtB6_9AutoTraitEL_j3_NtB2_3Bar6method)
+                //[v0]~| ERROR demangling(<[&dyn impl1[317d481089b8c8fe]::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1[317d481089b8c8fe]::AutoTrait; 3: usize] as impl1[317d481089b8c8fe]::main::{closure#1}::Bar>::method)
+                //[v0]~| ERROR demangling-alt(<[&dyn impl1::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1::AutoTrait; 3] as impl1::main::{closure#1}::Bar>::method)
             #[rustc_def_path]
-            //[legacy]~^ ERROR def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8)> + AutoTrait; _] as main::{{closure}}#1::Bar>::method)
-               //[v0]~^^ ERROR def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8)> + AutoTrait; _] as main::{{closure}}#1::Bar>::method)
+            //[legacy]~^ ERROR def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8, ...)> + AutoTrait; _] as main::{{closure}}#1::Bar>::method)
+               //[v0]~^^ ERROR def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8, ...)> + AutoTrait; _] as main::{{closure}}#1::Bar>::method)
             fn method(&self) {}
         }
     };
diff --git a/src/test/ui/symbol-names/impl1.v0.stderr b/src/test/ui/symbol-names/impl1.v0.stderr
index e024799df867c..01fe39ddf6cf9 100644
--- a/src/test/ui/symbol-names/impl1.v0.stderr
+++ b/src/test/ui/symbol-names/impl1.v0.stderr
@@ -46,26 +46,26 @@ error: def-path(bar::<impl foo::Foo>::baz)
 LL |         #[rustc_def_path]
    |         ^^^^^^^^^^^^^^^^^
 
-error: symbol-name(_RNvXNCNvCs4fqI2P2rA04_5impl14mains_0ARDNtB6_3Foop5AssocFG_KCRL0_hEuNtB6_9AutoTraitEL_j3_NtB2_3Bar6method)
-  --> $DIR/impl1.rs:63:13
+error: symbol-name(_RNvXNCNvCs4fqI2P2rA04_5impl14mains_0ARDNtB6_3Foop5AssocFG_KCRL0_hvEuNtB6_9AutoTraitEL_j3_NtB2_3Bar6method)
+  --> $DIR/impl1.rs:61:13
    |
 LL |             #[rustc_symbol_name]
    |             ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(<[&dyn impl1[317d481089b8c8fe]::Foo<Assoc = for<'a> extern "C" fn(&'a u8)> + impl1[317d481089b8c8fe]::AutoTrait; 3: usize] as impl1[317d481089b8c8fe]::main::{closure#1}::Bar>::method)
-  --> $DIR/impl1.rs:63:13
+error: demangling(<[&dyn impl1[317d481089b8c8fe]::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1[317d481089b8c8fe]::AutoTrait; 3: usize] as impl1[317d481089b8c8fe]::main::{closure#1}::Bar>::method)
+  --> $DIR/impl1.rs:61:13
    |
 LL |             #[rustc_symbol_name]
    |             ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling-alt(<[&dyn impl1::Foo<Assoc = for<'a> extern "C" fn(&'a u8)> + impl1::AutoTrait; 3] as impl1::main::{closure#1}::Bar>::method)
-  --> $DIR/impl1.rs:63:13
+error: demangling-alt(<[&dyn impl1::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1::AutoTrait; 3] as impl1::main::{closure#1}::Bar>::method)
+  --> $DIR/impl1.rs:61:13
    |
 LL |             #[rustc_symbol_name]
    |             ^^^^^^^^^^^^^^^^^^^^
 
-error: def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8)> + AutoTrait; _] as main::{{closure}}#1::Bar>::method)
-  --> $DIR/impl1.rs:70:13
+error: def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8, ...)> + AutoTrait; _] as main::{{closure}}#1::Bar>::method)
+  --> $DIR/impl1.rs:68:13
    |
 LL |             #[rustc_def_path]
    |             ^^^^^^^^^^^^^^^^^

From 003c5ec463a963b14b1a3de8545cc7aaf275cc8b Mon Sep 17 00:00:00 2001
From: Eduard-Mihai Burtescu <edy.burt@gmail.com>
Date: Mon, 12 Aug 2019 15:27:31 +0300
Subject: [PATCH 14/24] rustc_codegen_ssa: remove redundant `va_list_ref` field
 from `FunctionCx`.

---
 src/librustc_codegen_ssa/mir/block.rs | 12 +++++++-----
 src/librustc_codegen_ssa/mir/mod.rs   | 14 +-------------
 2 files changed, 8 insertions(+), 18 deletions(-)

diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index 0b9519f1c8079..7ebdfbdcdeb2d 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -1,3 +1,4 @@
+use rustc_data_structures::indexed_vec::Idx;
 use rustc::middle::lang_items;
 use rustc::ty::{self, Ty, TypeFoldable, Instance};
 use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, FnTypeExt};
@@ -224,14 +225,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     }
 
     fn codegen_return_terminator(&mut self, mut bx: Bx) {
+        // Call `va_end` if this is the definition of a C-variadic function.
         if self.fn_ty.c_variadic {
-            match self.va_list_ref {
-                Some(va_list) => {
+            // The `VaList` "spoofed" argument is just after all the real arguments.
+            let va_list_arg_idx = self.fn_ty.args.len();
+            match self.locals[mir::Local::new(1 + va_list_arg_idx)] {
+                LocalRef::Place(va_list) => {
                     bx.va_end(va_list.llval);
                 }
-                None => {
-                    bug!("C-variadic function must have a `va_list_ref`");
-                }
+                _ => bug!("C-variadic function must have a `VaList` place"),
             }
         }
         if self.fn_ty.ret.layout.abi.is_uninhabited() {
diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs
index 5f8ffaad3d4fd..4f3a8bdb540b5 100644
--- a/src/librustc_codegen_ssa/mir/mod.rs
+++ b/src/librustc_codegen_ssa/mir/mod.rs
@@ -81,10 +81,6 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
 
     /// Debug information for MIR scopes.
     scopes: IndexVec<mir::SourceScope, debuginfo::MirDebugScope<Bx::DIScope>>,
-
-    /// If this function is a C-variadic function, this contains the `PlaceRef` of the
-    /// "spoofed" `VaListImpl`.
-    va_list_ref: Option<PlaceRef<'tcx, Bx::Value>>,
 }
 
 impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
@@ -236,18 +232,13 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         scopes,
         locals: IndexVec::new(),
         debug_context,
-        va_list_ref: None,
     };
 
     let memory_locals = analyze::non_ssa_locals(&fx);
 
     // Allocate variable and temp allocas
     fx.locals = {
-        // FIXME(dlrobertson): This is ugly. Find a better way of getting the `PlaceRef` or
-        // `LocalRef` from `arg_local_refs`
-        let mut va_list_ref = None;
-        let args = arg_local_refs(&mut bx, &fx, &memory_locals, &mut va_list_ref);
-        fx.va_list_ref = va_list_ref;
+        let args = arg_local_refs(&mut bx, &fx, &memory_locals);
 
         let mut allocate_local = |local| {
             let decl = &mir.local_decls[local];
@@ -426,7 +417,6 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     bx: &mut Bx,
     fx: &FunctionCx<'a, 'tcx, Bx>,
     memory_locals: &BitSet<mir::Local>,
-    va_list_ref: &mut Option<PlaceRef<'tcx, Bx::Value>>,
 ) -> Vec<LocalRef<'tcx, Bx::Value>> {
     let mir = fx.mir;
     let tcx = fx.cx.tcx();
@@ -500,8 +490,6 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
             let va_list = PlaceRef::alloca(bx, bx.layout_of(arg_ty));
             bx.set_var_name(va_list.llval, name);
             bx.va_start(va_list.llval);
-            // FIXME(eddyb) remove `va_list_ref`.
-            *va_list_ref = Some(va_list);
 
             arg_scope.map(|scope| {
                 let variable_access = VariableAccess::DirectVariable {

From faee8e1756dbdfbe0752a8006e952395c0cd7a67 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 25 Sep 2019 17:05:30 -0700
Subject: [PATCH 15/24] Turn `walk_parent_nodes` method into an iterator

---
 src/librustc/hir/map/mod.rs | 206 ++++++++++++++++++------------------
 1 file changed, 101 insertions(+), 105 deletions(-)

diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index d4efe0297b671..ca854395d7bbb 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -23,8 +23,6 @@ use syntax::source_map::Spanned;
 use syntax::ext::base::MacroKind;
 use syntax_pos::{Span, DUMMY_SP};
 
-use std::result::Result::Err;
-
 pub mod blocks;
 mod collector;
 mod def_collector;
@@ -183,6 +181,44 @@ pub struct Map<'hir> {
     hir_to_node_id: FxHashMap<HirId, NodeId>,
 }
 
+struct ParentHirIterator<'map> {
+    current_id: HirId,
+    map: &'map Map<'map>,
+}
+
+impl<'map> ParentHirIterator<'map> {
+    fn new(current_id: HirId, map: &'map Map<'map>) -> ParentHirIterator<'map> {
+        ParentHirIterator {
+            current_id,
+            map,
+        }
+    }
+}
+
+impl<'map> Iterator for ParentHirIterator<'map> {
+    type Item = (HirId, Node<'map>);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.current_id == CRATE_HIR_ID {
+            return None;
+        }
+        loop { // There are nodes that do not have entries, so we need to skip them.
+            let parent_id = self.map.get_parent_node(self.current_id);
+
+            if parent_id == self.current_id {
+                self.current_id = CRATE_HIR_ID;
+                return None;
+            }
+
+            self.current_id = parent_id;
+            if let Some(entry) = self.map.find_entry(parent_id) {
+                return Some((parent_id, entry.node));
+            }
+            // If this `HirId` doesn't have an `Entry`, skip it and look for its `parent_id`.
+        }
+    }
+}
+
 impl<'hir> Map<'hir> {
     #[inline]
     fn lookup(&self, id: HirId) -> Option<&Entry<'hir>> {
@@ -682,45 +718,6 @@ impl<'hir> Map<'hir> {
         }
     }
 
-
-    /// If there is some error when walking the parents (e.g., a node does not
-    /// have a parent in the map or a node can't be found), then we return the
-    /// last good `HirId` we found. Note that reaching the crate root (`id == 0`),
-    /// is not an error, since items in the crate module have the crate root as
-    /// parent.
-    fn walk_parent_nodes<F, F2>(&self,
-                                start_id: HirId,
-                                found: F,
-                                bail_early: F2)
-        -> Result<HirId, HirId>
-        where F: Fn(&Node<'hir>) -> bool, F2: Fn(&Node<'hir>) -> bool
-    {
-        let mut id = start_id;
-        loop {
-            let parent_id = self.get_parent_node(id);
-            if parent_id == CRATE_HIR_ID {
-                return Ok(CRATE_HIR_ID);
-            }
-            if parent_id == id {
-                return Err(id);
-            }
-
-            if let Some(entry) = self.find_entry(parent_id) {
-                if let Node::Crate = entry.node {
-                    return Err(id);
-                }
-                if found(&entry.node) {
-                    return Ok(parent_id);
-                } else if bail_early(&entry.node) {
-                    return Err(parent_id);
-                }
-                id = parent_id;
-            } else {
-                return Err(id);
-            }
-        }
-    }
-
     /// Retrieves the `HirId` for `id`'s enclosing method, unless there's a
     /// `while` or `loop` before reaching it, as block tail returns are not
     /// available in them.
@@ -744,29 +741,23 @@ impl<'hir> Map<'hir> {
     /// }
     /// ```
     pub fn get_return_block(&self, id: HirId) -> Option<HirId> {
-        let match_fn = |node: &Node<'_>| {
-            match *node {
+        for (hir_id, node) in ParentHirIterator::new(id, &self) {
+            match node {
                 Node::Item(_) |
                 Node::ForeignItem(_) |
                 Node::TraitItem(_) |
                 Node::Expr(Expr { kind: ExprKind::Closure(..), ..}) |
-                Node::ImplItem(_) => true,
-                _ => false,
-            }
-        };
-        let match_non_returning_block = |node: &Node<'_>| {
-            match *node {
+                Node::ImplItem(_) => return Some(hir_id),
                 Node::Expr(ref expr) => {
                     match expr.kind {
-                        ExprKind::Loop(..) | ExprKind::Ret(..) => true,
-                        _ => false,
+                        ExprKind::Loop(..) | ExprKind::Ret(..) => return None,
+                        _ => {}
                     }
                 }
-                _ => false,
+                _ => {}
             }
-        };
-
-        self.walk_parent_nodes(id, match_fn, match_non_returning_block).ok()
+        }
+        None
     }
 
     /// Retrieves the `HirId` for `id`'s parent item, or `id` itself if no
@@ -774,16 +765,17 @@ impl<'hir> Map<'hir> {
     /// in the HIR which is recorded by the map and is an item, either an item
     /// in a module, trait, or impl.
     pub fn get_parent_item(&self, hir_id: HirId) -> HirId {
-        match self.walk_parent_nodes(hir_id, |node| match *node {
-            Node::Item(_) |
-            Node::ForeignItem(_) |
-            Node::TraitItem(_) |
-            Node::ImplItem(_) => true,
-            _ => false,
-        }, |_| false) {
-            Ok(id) => id,
-            Err(id) => id,
+        for (hir_id, node) in ParentHirIterator::new(hir_id, &self) {
+            match node {
+                Node::Crate |
+                Node::Item(_) |
+                Node::ForeignItem(_) |
+                Node::TraitItem(_) |
+                Node::ImplItem(_) => return hir_id,
+                _ => {}
+            }
         }
+        hir_id
     }
 
     /// Returns the `DefId` of `id`'s nearest module parent, or `id` itself if no
@@ -795,58 +787,62 @@ impl<'hir> Map<'hir> {
     /// Returns the `HirId` of `id`'s nearest module parent, or `id` itself if no
     /// module parent is in this map.
     pub fn get_module_parent_node(&self, hir_id: HirId) -> HirId {
-        match self.walk_parent_nodes(hir_id, |node| match *node {
-            Node::Item(&Item { kind: ItemKind::Mod(_), .. }) => true,
-            _ => false,
-        }, |_| false) {
-            Ok(id) => id,
-            Err(id) => id,
+        for (hir_id, node) in ParentHirIterator::new(hir_id, &self) {
+            if let Node::Item(&Item { kind: ItemKind::Mod(_), .. }) = node {
+                return hir_id;
+            }
         }
+        CRATE_HIR_ID
     }
 
     /// Returns the nearest enclosing scope. A scope is roughly an item or block.
     pub fn get_enclosing_scope(&self, hir_id: HirId) -> Option<HirId> {
-        self.walk_parent_nodes(hir_id, |node| match *node {
-            Node::Item(i) => {
-                match i.kind {
-                    ItemKind::Fn(..)
-                    | ItemKind::Mod(..)
-                    | ItemKind::Enum(..)
-                    | ItemKind::Struct(..)
-                    | ItemKind::Union(..)
-                    | ItemKind::Trait(..)
-                    | ItemKind::Impl(..) => true,
-                    _ => false,
-                }
-            },
-            Node::ForeignItem(fi) => {
-                match fi.kind {
-                    ForeignItemKind::Fn(..) => true,
-                    _ => false,
-                }
-            },
-            Node::TraitItem(ti) => {
-                match ti.kind {
-                    TraitItemKind::Method(..) => true,
-                    _ => false,
-                }
-            },
-            Node::ImplItem(ii) => {
-                match ii.kind {
-                    ImplItemKind::Method(..) => true,
-                    _ => false,
-                }
-            },
-            Node::Block(_) => true,
-            _ => false,
-        }, |_| false).ok()
+        for (hir_id, node) in ParentHirIterator::new(hir_id, &self) {
+            if match node {
+                Node::Item(i) => {
+                    match i.kind {
+                        ItemKind::Fn(..)
+                        | ItemKind::Mod(..)
+                        | ItemKind::Enum(..)
+                        | ItemKind::Struct(..)
+                        | ItemKind::Union(..)
+                        | ItemKind::Trait(..)
+                        | ItemKind::Impl(..) => true,
+                        _ => false,
+                    }
+                },
+                Node::ForeignItem(fi) => {
+                    match fi.kind {
+                        ForeignItemKind::Fn(..) => true,
+                        _ => false,
+                    }
+                },
+                Node::TraitItem(ti) => {
+                    match ti.kind {
+                        TraitItemKind::Method(..) => true,
+                        _ => false,
+                    }
+                },
+                Node::ImplItem(ii) => {
+                    match ii.kind {
+                        ImplItemKind::Method(..) => true,
+                        _ => false,
+                    }
+                },
+                Node::Block(_) => true,
+                _ => false,
+            } {
+                return Some(hir_id);
+            }
+        }
+        None
     }
 
     /// Returns the defining scope for an opaque type definition.
     pub fn get_defining_scope(&self, id: HirId) -> Option<HirId> {
         let mut scope = id;
         loop {
-            scope = self.get_enclosing_scope(scope)?;
+            scope = self.get_enclosing_scope(scope).unwrap_or(CRATE_HIR_ID);
             if scope == CRATE_HIR_ID {
                 return Some(CRATE_HIR_ID);
             }

From 46a38dc183d2f79b764b2cca0011d0843f0fffcb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 25 Sep 2019 23:01:01 -0700
Subject: [PATCH 16/24] Account for tail expressions when pointing at return
 type

When there's a type mismatch we make an effort to check if it was
caused by a function's return type. This logic now makes sure to
only point at the return type if the error happens in a tail
expression.
---
 src/librustc/hir/map/mod.rs                   | 25 ++++++++++++++++++-
 src/librustc/hir/mod.rs                       |  2 +-
 src/librustc_typeck/check/expr.rs             |  8 ++++--
 .../ui/struct-literal-variant-in-if.stderr    |  3 ---
 4 files changed, 31 insertions(+), 7 deletions(-)

diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index ca854395d7bbb..9854d8b04fd98 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -741,7 +741,28 @@ impl<'hir> Map<'hir> {
     /// }
     /// ```
     pub fn get_return_block(&self, id: HirId) -> Option<HirId> {
-        for (hir_id, node) in ParentHirIterator::new(id, &self) {
+        let mut iter = ParentHirIterator::new(id, &self).peekable();
+        let mut ignore_tail = false;
+        if let Some(entry) = self.find_entry(id) {
+            if let Node::Expr(Expr { node: ExprKind::Ret(_), .. }) = entry.node {
+                // When dealing with `return` statements, we don't care about climbing only tail
+                // expressions.
+                ignore_tail = true;
+            }
+        }
+        while let Some((hir_id, node)) = iter.next() {
+            if let (Some((_, next_node)), false) = (iter.peek(), ignore_tail) {
+                match next_node {
+                    Node::Block(Block { expr: None, .. }) => return None,
+                    Node::Block(Block { expr: Some(expr), .. }) => {
+                        if hir_id != expr.hir_id {
+                            // The current node is not the tail expression of its parent.
+                            return None;
+                        }
+                    }
+                    _ => {}
+                }
+            }
             match node {
                 Node::Item(_) |
                 Node::ForeignItem(_) |
@@ -750,10 +771,12 @@ impl<'hir> Map<'hir> {
                 Node::ImplItem(_) => return Some(hir_id),
                 Node::Expr(ref expr) => {
                     match expr.kind {
+                        // Ignore `return`s on the first iteration
                         ExprKind::Loop(..) | ExprKind::Ret(..) => return None,
                         _ => {}
                     }
                 }
+                Node::Local(_) => return None,
                 _ => {}
             }
         }
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 01cb5cc9bc105..0b1fcd0da3a9c 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1563,7 +1563,7 @@ pub enum ExprKind {
     /// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
     /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d])`.
     MethodCall(P<PathSegment>, Span, HirVec<Expr>),
-    /// A tuple (e.g., `(a, b, c ,d)`).
+    /// A tuple (e.g., `(a, b, c, d)`).
     Tup(HirVec<Expr>),
     /// A binary operation (e.g., `a + b`, `a * b`).
     Binary(BinOp, P<Expr>, P<Expr>),
diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index 58f41ca4f88f9..317d829d135bf 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -620,8 +620,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expr: &'tcx hir::Expr
     ) -> Ty<'tcx> {
         if self.ret_coercion.is_none() {
-            struct_span_err!(self.tcx.sess, expr.span, E0572,
-                                "return statement outside of function body").emit();
+            struct_span_err!(
+                self.tcx.sess,
+                expr.span,
+                E0572,
+                "return statement outside of function body",
+            ).emit();
         } else if let Some(ref e) = expr_opt {
             if self.ret_coercion_span.borrow().is_none() {
                 *self.ret_coercion_span.borrow_mut() = Some(e.span);
diff --git a/src/test/ui/struct-literal-variant-in-if.stderr b/src/test/ui/struct-literal-variant-in-if.stderr
index f91b9d7dce60f..85cbc787bc2db 100644
--- a/src/test/ui/struct-literal-variant-in-if.stderr
+++ b/src/test/ui/struct-literal-variant-in-if.stderr
@@ -49,9 +49,6 @@ LL |     if x == E::V { field } {}
 error[E0308]: mismatched types
   --> $DIR/struct-literal-variant-in-if.rs:10:20
    |
-LL | fn test_E(x: E) {
-   |                 - help: try adding a return type: `-> bool`
-LL |     let field = true;
 LL |     if x == E::V { field } {}
    |                    ^^^^^ expected (), found bool
    |

From e537d066f20555b901fcf8381ee61462de4b8a67 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Thu, 26 Sep 2019 14:38:01 -0700
Subject: [PATCH 17/24] review comments

---
 src/librustc/hir/map/mod.rs            | 6 +++---
 src/librustc/infer/opaque_types/mod.rs | 2 +-
 src/librustc_typeck/collect.rs         | 4 +---
 3 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index 9854d8b04fd98..d6e3a675be0c8 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -862,12 +862,12 @@ impl<'hir> Map<'hir> {
     }
 
     /// Returns the defining scope for an opaque type definition.
-    pub fn get_defining_scope(&self, id: HirId) -> Option<HirId> {
+    pub fn get_defining_scope(&self, id: HirId) -> HirId {
         let mut scope = id;
         loop {
             scope = self.get_enclosing_scope(scope).unwrap_or(CRATE_HIR_ID);
             if scope == CRATE_HIR_ID {
-                return Some(CRATE_HIR_ID);
+                return CRATE_HIR_ID;
             }
             match self.get(scope) {
                 Node::Item(i) => {
@@ -880,7 +880,7 @@ impl<'hir> Map<'hir> {
                 _ => break,
             }
         }
-        Some(scope)
+        scope
     }
 
     pub fn get_parent_did(&self, id: HirId) -> DefId {
diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs
index 3b3649fd8112f..35f47e252a7c5 100644
--- a/src/librustc/infer/opaque_types/mod.rs
+++ b/src/librustc/infer/opaque_types/mod.rs
@@ -1215,7 +1215,7 @@ pub fn may_define_opaque_type(
     let mut hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
 
     // Named opaque types can be defined by any siblings or children of siblings.
-    let scope = tcx.hir().get_defining_scope(opaque_hir_id).expect("could not get defining scope");
+    let scope = tcx.hir().get_defining_scope(opaque_hir_id);
     // We walk up the node tree until we hit the root or the scope of the opaque type.
     while hir_id != scope && hir_id != hir::CRATE_HIR_ID {
         hir_id = tcx.hir().get_parent_item(hir_id);
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 3ac3ce2a02c2e..db017394cd5f1 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1717,9 +1717,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
     }
 
     let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
-    let scope = tcx.hir()
-        .get_defining_scope(hir_id)
-        .expect("could not get defining scope");
+    let scope = tcx.hir().get_defining_scope(hir_id);
     let mut locator = ConstraintLocator {
         def_id,
         tcx,

From a284822e009e1e72443041219c7f3646c822ff89 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Fri, 27 Sep 2019 09:47:37 -0700
Subject: [PATCH 18/24] fix rebase

---
 src/librustc/hir/map/mod.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index d6e3a675be0c8..b45d3f0396047 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -744,7 +744,7 @@ impl<'hir> Map<'hir> {
         let mut iter = ParentHirIterator::new(id, &self).peekable();
         let mut ignore_tail = false;
         if let Some(entry) = self.find_entry(id) {
-            if let Node::Expr(Expr { node: ExprKind::Ret(_), .. }) = entry.node {
+            if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = entry.node {
                 // When dealing with `return` statements, we don't care about climbing only tail
                 // expressions.
                 ignore_tail = true;

From d559b725d3ac28b90607c0823fc5639d69053e10 Mon Sep 17 00:00:00 2001
From: Mark Rousskov <mark.simulacrum@gmail.com>
Date: Fri, 27 Sep 2019 13:29:22 -0400
Subject: [PATCH 19/24] Add mailmap entry for Dustin Bensing by request

---
 .mailmap | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.mailmap b/.mailmap
index 9587aaab35945..a2e3c581eabba 100644
--- a/.mailmap
+++ b/.mailmap
@@ -69,6 +69,7 @@ David Manescu <david.manescu@gmail.com> <dman2626@uni.sydney.edu.au>
 David Ross <daboross@daboross.net>
 Derek Chiang <derekchiang93@gmail.com> Derek Chiang (Enchi Jiang) <derekchiang93@gmail.com>
 Diggory Hardy <diggory.hardy@gmail.com> Diggory Hardy <github@dhardy.name>
+Dustin Bensing <dustin.bensing@googlemail.com>
 Dylan Braithwaite <dylanbraithwaite1@gmail.com> <mail@dylanb.me>
 Dzmitry Malyshau <kvarkus@gmail.com>
 E. Dunham <edunham@mozilla.com> edunham <edunham@mozilla.com>

From d540d44c711d0ef9317aa4b8e8b563321e3c35bb Mon Sep 17 00:00:00 2001
From: Mark Rousskov <mark.simulacrum@gmail.com>
Date: Wed, 25 Sep 2019 15:36:14 -0400
Subject: [PATCH 20/24] Remove global_tcx from TyCtxt

The non-global context was removed; there's only one context now. This
is a noop method that only serves to confuse readers -- remove it.
---
 src/librustc/dep_graph/graph.rs                |  2 +-
 src/librustc/infer/mod.rs                      |  2 +-
 src/librustc/infer/opaque_types/mod.rs         |  6 ++----
 src/librustc/middle/intrinsicck.rs             |  2 +-
 src/librustc/middle/mem_categorization.rs      |  2 +-
 src/librustc/traits/chalk_fulfill.rs           |  2 +-
 src/librustc/traits/error_reporting.rs         |  7 +++----
 src/librustc/traits/fulfill.rs                 |  2 +-
 src/librustc/traits/query/dropck_outlives.rs   |  3 +--
 .../traits/query/evaluate_obligation.rs        |  2 +-
 src/librustc/traits/query/normalize.rs         |  4 ++--
 src/librustc/traits/query/outlives_bounds.rs   |  2 +-
 src/librustc/traits/select.rs                  |  2 +-
 .../traits/specialize/specialization_graph.rs  |  1 -
 src/librustc/traits/util.rs                    |  3 +--
 src/librustc/ty/context.rs                     | 18 +++++-------------
 src/librustc/ty/instance.rs                    |  2 +-
 src/librustc/ty/layout.rs                      |  6 +++---
 src/librustc/ty/mod.rs                         |  8 ++++----
 src/librustc/ty/query/plumbing.rs              | 16 ++++++++--------
 src/librustc_macros/src/query.rs               |  4 ++--
 src/librustc_mir/borrow_check/mod.rs           |  6 +++---
 .../borrow_check/nll/type_check/mod.rs         |  3 +--
 .../borrow_check/nll/universal_regions.rs      |  5 ++---
 src/librustc_mir/dataflow/drop_flag_effects.rs |  3 +--
 src/librustc_mir/hair/cx/expr.rs               |  4 ++--
 src/librustc_mir/hair/cx/mod.rs                |  9 ++++-----
 src/librustc_mir/shim.rs                       |  2 +-
 src/librustc_typeck/astconv.rs                 |  2 +-
 src/librustc_typeck/check/expr.rs              |  4 ++--
 src/librustc_typeck/check/wfcheck.rs           |  2 +-
 31 files changed, 59 insertions(+), 77 deletions(-)

diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs
index e76a70350b33e..acfdc91523f70 100644
--- a/src/librustc/dep_graph/graph.rs
+++ b/src/librustc/dep_graph/graph.rs
@@ -590,7 +590,7 @@ impl DepGraph {
                 // mark it as green by recursively marking all of its
                 // dependencies green.
                 self.try_mark_previous_green(
-                    tcx.global_tcx(),
+                    tcx,
                     data,
                     prev_index,
                     &dep_node
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index ca07496afed08..acb018f2d34d7 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -1460,7 +1460,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         // type-checking closure types are in local tables only.
         if !self.in_progress_tables.is_some() || !ty.has_closure_types() {
             if !(param_env, ty).has_local_value() {
-                return ty.is_copy_modulo_regions(self.tcx.global_tcx(), param_env, span);
+                return ty.is_copy_modulo_regions(self.tcx, param_env, span);
             }
         }
 
diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs
index 3b3649fd8112f..7e7b4f2a17a40 100644
--- a/src/librustc/infer/opaque_types/mod.rs
+++ b/src/librustc/infer/opaque_types/mod.rs
@@ -561,15 +561,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             def_id, instantiated_ty
         );
 
-        let gcx = self.tcx.global_tcx();
-
         // Use substs to build up a reverse map from regions to their
         // identity mappings. This is necessary because of `impl
         // Trait` lifetimes are computed by replacing existing
         // lifetimes with 'static and remapping only those used in the
         // `impl Trait` return type, resulting in the parameters
         // shifting.
-        let id_substs = InternalSubsts::identity_for_item(gcx, def_id);
+        let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id);
         let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> = opaque_defn
             .substs
             .iter()
@@ -854,7 +852,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
                     )
                     .emit();
 
-                self.tcx().global_tcx().mk_region(ty::ReStatic)
+                self.tcx().mk_region(ty::ReStatic)
             },
         }
     }
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index ecca62349c985..c1435551a5918 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -82,7 +82,7 @@ impl ExprVisitor<'tcx> {
 
             // Special-case transmutting from `typeof(function)` and
             // `Option<typeof(function)>` to present a clearer error.
-            let from = unpack_option_like(self.tcx.global_tcx(), from);
+            let from = unpack_option_like(self.tcx, from);
             if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (&from.kind, sk_to) {
                 if size_to == Pointer.size(&self.tcx) {
                     struct_span_err!(self.tcx.sess, span, E0591,
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index c6a46f60927e8..3f5f54c94638e 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -749,7 +749,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
                              .unwrap_or(ty::ClosureKind::LATTICE_BOTTOM),
 
                     None =>
-                        closure_substs.closure_kind(closure_def_id, self.tcx.global_tcx()),
+                        closure_substs.closure_kind(closure_def_id, self.tcx),
                 }
             }
             _ => span_bug!(span, "unexpected type for fn in mem_categorization: {:?}", ty),
diff --git a/src/librustc/traits/chalk_fulfill.rs b/src/librustc/traits/chalk_fulfill.rs
index a7e1f2a6a73a7..d9e83df7ddda6 100644
--- a/src/librustc/traits/chalk_fulfill.rs
+++ b/src/librustc/traits/chalk_fulfill.rs
@@ -108,7 +108,7 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
                     goal: obligation.goal.predicate,
                 }, &mut orig_values);
 
-                match infcx.tcx.global_tcx().evaluate_goal(canonical_goal) {
+                match infcx.tcx.evaluate_goal(canonical_goal) {
                     Ok(response) => {
                         if response.is_proven() {
                             making_progress = true;
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 1ce5d72ba848e..c2d531793372a 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -497,7 +497,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             4
         };
 
-        let normalize = |candidate| self.tcx.global_tcx().infer_ctxt().enter(|ref infcx| {
+        let normalize = |candidate| self.tcx.infer_ctxt().enter(|ref infcx| {
             let normalized = infcx
                 .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
                 .normalize(candidate)
@@ -783,8 +783,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     }
 
                     ty::Predicate::ObjectSafe(trait_def_id) => {
-                        let violations = self.tcx.global_tcx()
-                            .object_safety_violations(trait_def_id);
+                        let violations = self.tcx.object_safety_violations(trait_def_id);
                         if let Some(err) = self.tcx.report_object_safety_error(
                             span,
                             trait_def_id,
@@ -920,7 +919,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             }
 
             TraitNotObjectSafe(did) => {
-                let violations = self.tcx.global_tcx().object_safety_violations(did);
+                let violations = self.tcx.object_safety_violations(did);
                 if let Some(err) = self.tcx.report_object_safety_error(span, did, violations) {
                     err
                 } else {
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index 0a190af1f986d..a981162fdc326 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -495,7 +495,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
                 } else {
                     if !substs.has_local_value() {
                         let instance = ty::Instance::resolve(
-                            self.selcx.tcx().global_tcx(),
+                            self.selcx.tcx(),
                             obligation.param_env,
                             def_id,
                             substs,
diff --git a/src/librustc/traits/query/dropck_outlives.rs b/src/librustc/traits/query/dropck_outlives.rs
index c3c43132d8540..aa30541610e9b 100644
--- a/src/librustc/traits/query/dropck_outlives.rs
+++ b/src/librustc/traits/query/dropck_outlives.rs
@@ -40,12 +40,11 @@ impl<'cx, 'tcx> At<'cx, 'tcx> {
             };
         }
 
-        let gcx = tcx.global_tcx();
         let mut orig_values = OriginalQueryValues::default();
         let c_ty = self.infcx.canonicalize_query(&self.param_env.and(ty), &mut orig_values);
         let span = self.cause.span;
         debug!("c_ty = {:?}", c_ty);
-        if let Ok(result) = &gcx.dropck_outlives(c_ty) {
+        if let Ok(result) = &tcx.dropck_outlives(c_ty) {
             if result.is_proven() {
                 if let Ok(InferOk { value, obligations }) =
                     self.infcx.instantiate_query_response_and_region_obligations(
diff --git a/src/librustc/traits/query/evaluate_obligation.rs b/src/librustc/traits/query/evaluate_obligation.rs
index b9557ceaa6d9f..17684df7e9b8e 100644
--- a/src/librustc/traits/query/evaluate_obligation.rs
+++ b/src/librustc/traits/query/evaluate_obligation.rs
@@ -50,7 +50,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
         // Run canonical query. If overflow occurs, rerun from scratch but this time
         // in standard trait query mode so that overflow is handled appropriately
         // within `SelectionContext`.
-        self.tcx.global_tcx().evaluate_obligation(c_pred)
+        self.tcx.evaluate_obligation(c_pred)
     }
 
     // Helper function that canonicalizes and runs the query. If an
diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs
index b334e6dd8f84e..ab42eab28440f 100644
--- a/src/librustc/traits/query/normalize.rs
+++ b/src/librustc/traits/query/normalize.rs
@@ -141,7 +141,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
                 // binder). It would be better to normalize in a
                 // binding-aware fashion.
 
-                let gcx = self.infcx.tcx.global_tcx();
+                let tcx = self.infcx.tcx;
 
                 let mut orig_values = OriginalQueryValues::default();
                 // HACK(matthewjasper) `'static` is special-cased in selection,
@@ -150,7 +150,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
                     &self.param_env.and(*data), &mut orig_values);
                 debug!("QueryNormalizer: c_data = {:#?}", c_data);
                 debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
-                match gcx.normalize_projection_ty(c_data) {
+                match tcx.normalize_projection_ty(c_data) {
                     Ok(result) => {
                         // We don't expect ambiguity.
                         if result.is_ambiguous() {
diff --git a/src/librustc/traits/query/outlives_bounds.rs b/src/librustc/traits/query/outlives_bounds.rs
index 40bd18738b528..f5808b6b5faaf 100644
--- a/src/librustc/traits/query/outlives_bounds.rs
+++ b/src/librustc/traits/query/outlives_bounds.rs
@@ -97,7 +97,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
 
         let mut orig_values = OriginalQueryValues::default();
         let key = self.canonicalize_query(&param_env.and(ty), &mut orig_values);
-        let result = match self.tcx.global_tcx().implied_outlives_bounds(key) {
+        let result = match self.tcx.implied_outlives_bounds(key) {
             Ok(r) => r,
             Err(NoSolution) => {
                 self.tcx.sess.delay_span_bug(
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 911ecef802425..e1ca9a16d965f 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -2491,7 +2491,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 if other.evaluation.must_apply_modulo_regions() {
                     match victim.candidate {
                         ImplCandidate(victim_def) => {
-                            let tcx = self.tcx().global_tcx();
+                            let tcx = self.tcx();
                             return tcx.specializes((other_def, victim_def))
                                 || tcx.impls_are_allowed_to_overlap(
                                     other_def, victim_def).is_some();
diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs
index 8cbadebaea5a5..ce0f43021378b 100644
--- a/src/librustc/traits/specialize/specialization_graph.rs
+++ b/src/librustc/traits/specialize/specialization_graph.rs
@@ -162,7 +162,6 @@ impl<'tcx> Children {
                 }
             };
 
-            let tcx = tcx.global_tcx();
             let (le, ge) = traits::overlapping_impls(
                 tcx,
                 possible_sibling,
diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs
index 6d0347563d003..18ec2241b2df8 100644
--- a/src/librustc/traits/util.rs
+++ b/src/librustc/traits/util.rs
@@ -661,8 +661,7 @@ impl<'tcx> TyCtxt<'tcx> {
                 }
             }
             None => {
-                self.global_tcx()
-                    .impl_defaultness(node_item_def_id)
+                self.impl_defaultness(node_item_def_id)
                     .is_default()
             }
         }
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 3c511cb4d188d..2d68ad7fbd5c1 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -1067,14 +1067,6 @@ pub struct GlobalCtxt<'tcx> {
 }
 
 impl<'tcx> TyCtxt<'tcx> {
-    /// Gets the global `TyCtxt`.
-    #[inline]
-    pub fn global_tcx(self) -> TyCtxt<'tcx> {
-        TyCtxt {
-            gcx: self.gcx,
-        }
-    }
-
     #[inline(always)]
     pub fn hir(self) -> &'tcx hir_map::Map<'tcx> {
         &self.hir_map
@@ -1158,7 +1150,7 @@ impl<'tcx> TyCtxt<'tcx> {
 
     /// Like lift, but only tries in the global tcx.
     pub fn lift_to_global<T: ?Sized + Lift<'tcx>>(self, value: &T) -> Option<T::Lifted> {
-        value.lift_to_tcx(self.global_tcx())
+        value.lift_to_tcx(self)
     }
 
     /// Creates a type context and call the closure with a `TyCtxt` reference
@@ -1432,7 +1424,7 @@ impl<'tcx> TyCtxt<'tcx> {
                                            -> Result<(), E::Error>
         where E: ty::codec::TyEncoder
     {
-        self.queries.on_disk_cache.serialize(self.global_tcx(), encoder)
+        self.queries.on_disk_cache.serialize(self, encoder)
     }
 
     /// If `true`, we should use the AST-based borrowck (we may *also* use
@@ -1606,7 +1598,7 @@ impl<'tcx> GlobalCtxt<'tcx> {
         let tcx = TyCtxt {
             gcx: self,
         };
-        ty::tls::with_related_context(tcx.global_tcx(), |icx| {
+        ty::tls::with_related_context(tcx, |icx| {
             let new_icx = ty::tls::ImplicitCtxt {
                 tcx,
                 query: icx.query.clone(),
@@ -2431,7 +2423,7 @@ impl<'tcx> TyCtxt<'tcx> {
 
     #[inline]
     pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> {
-        self.mk_ty(Array(ty, ty::Const::from_usize(self.global_tcx(), n)))
+        self.mk_ty(Array(ty, ty::Const::from_usize(self, n)))
     }
 
     #[inline]
@@ -2646,7 +2638,7 @@ impl<'tcx> TyCtxt<'tcx> {
         if ts.len() == 0 {
             List::empty()
         } else {
-            self.global_tcx()._intern_canonical_var_infos(ts)
+            self._intern_canonical_var_infos(ts)
         }
     }
 
diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs
index ecb512b0cd1a2..741830f205cb0 100644
--- a/src/librustc/ty/instance.rs
+++ b/src/librustc/ty/instance.rs
@@ -210,7 +210,7 @@ impl<'tcx> Instance<'tcx> {
     }
 
     pub fn mono(tcx: TyCtxt<'tcx>, def_id: DefId) -> Instance<'tcx> {
-        Instance::new(def_id, tcx.global_tcx().empty_substs_for_def_id(def_id))
+        Instance::new(def_id, tcx.empty_substs_for_def_id(def_id))
     }
 
     #[inline]
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 790b0c5cb48f4..3accbdf9bcbc6 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -1883,7 +1883,7 @@ impl<'tcx> HasDataLayout for TyCtxt<'tcx> {
 
 impl<'tcx> HasTyCtxt<'tcx> for TyCtxt<'tcx> {
     fn tcx(&self) -> TyCtxt<'tcx> {
-        self.global_tcx()
+        *self
     }
 }
 
@@ -2003,7 +2003,7 @@ impl TyCtxt<'tcx> {
     pub fn layout_of(self, param_env_and_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>)
                      -> Result<TyLayout<'tcx>, LayoutError<'tcx>> {
         let cx = LayoutCx {
-            tcx: self.global_tcx(),
+            tcx: self,
             param_env: param_env_and_ty.param_env
         };
         cx.layout_of(param_env_and_ty.value)
@@ -2017,7 +2017,7 @@ impl ty::query::TyCtxtAt<'tcx> {
     pub fn layout_of(self, param_env_and_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>)
                      -> Result<TyLayout<'tcx>, LayoutError<'tcx>> {
         let cx = LayoutCx {
-            tcx: self.global_tcx().at(self.span),
+            tcx: self.at(self.span),
             param_env: param_env_and_ty.param_env
         };
         cx.layout_of(param_env_and_ty.value)
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index f107af0cd07ec..0e9600449f62c 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -2378,7 +2378,7 @@ impl<'tcx> AdtDef {
     pub fn eval_explicit_discr(&self, tcx: TyCtxt<'tcx>, expr_did: DefId) -> Option<Discr<'tcx>> {
         let param_env = tcx.param_env(expr_did);
         let repr_type = self.repr.discr_type();
-        let substs = InternalSubsts::identity_for_item(tcx.global_tcx(), expr_did);
+        let substs = InternalSubsts::identity_for_item(tcx, expr_did);
         let instance = ty::Instance::new(expr_did, substs);
         let cid = GlobalId {
             instance,
@@ -2387,7 +2387,7 @@ impl<'tcx> AdtDef {
         match tcx.const_eval(param_env.and(cid)) {
             Ok(val) => {
                 // FIXME: Find the right type and use it instead of `val.ty` here
-                if let Some(b) = val.try_eval_bits(tcx.global_tcx(), param_env, val.ty) {
+                if let Some(b) = val.try_eval_bits(tcx, param_env, val.ty) {
                     trace!("discriminants: {} ({:?})", b, repr_type);
                     Some(Discr {
                         val: b,
@@ -2423,7 +2423,7 @@ impl<'tcx> AdtDef {
         tcx: TyCtxt<'tcx>,
     ) -> impl Iterator<Item = (VariantIdx, Discr<'tcx>)> + Captures<'tcx> {
         let repr_type = self.repr.discr_type();
-        let initial = repr_type.initial_discriminant(tcx.global_tcx());
+        let initial = repr_type.initial_discriminant(tcx);
         let mut prev_discr = None::<Discr<'tcx>>;
         self.variants.iter_enumerated().map(move |(i, v)| {
             let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr(tcx));
@@ -2457,7 +2457,7 @@ impl<'tcx> AdtDef {
         let (val, offset) = self.discriminant_def_for_variant(variant_index);
         let explicit_value = val
             .and_then(|expr_did| self.eval_explicit_discr(tcx, expr_did))
-            .unwrap_or_else(|| self.repr.discr_type().initial_discriminant(tcx.global_tcx()));
+            .unwrap_or_else(|| self.repr.discr_type().initial_discriminant(tcx));
         explicit_value.checked_add(tcx, offset as u128).0
     }
 
diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs
index a1828bb5ab7a7..d247c0f9f69f3 100644
--- a/src/librustc/ty/query/plumbing.rs
+++ b/src/librustc/ty/query/plumbing.rs
@@ -265,7 +265,7 @@ impl<'tcx> TyCtxt<'tcx> {
         tls::with_related_context(self, move |current_icx| {
             // Update the `ImplicitCtxt` to point to our new query job.
             let new_icx = tls::ImplicitCtxt {
-                tcx: self.global_tcx(),
+                tcx: self,
                 query: Some(job),
                 diagnostics,
                 layout_depth: current_icx.layout_depth,
@@ -274,7 +274,7 @@ impl<'tcx> TyCtxt<'tcx> {
 
             // Use the `ImplicitCtxt` while we execute the query.
             tls::enter_context(&new_icx, |_| {
-                compute(self.global_tcx())
+                compute(self)
             })
         })
     }
@@ -384,7 +384,7 @@ impl<'tcx> TyCtxt<'tcx> {
             let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| {
                 self.start_query(job.job.clone(), diagnostics, |tcx| {
                     tcx.dep_graph.with_anon_task(Q::dep_kind(), || {
-                        Q::compute(tcx.global_tcx(), key)
+                        Q::compute(tcx, key)
                     })
                 })
             });
@@ -445,10 +445,10 @@ impl<'tcx> TyCtxt<'tcx> {
         debug_assert!(self.dep_graph.is_green(dep_node));
 
         // First we try to load the result from the on-disk cache.
-        let result = if Q::cache_on_disk(self.global_tcx(), key.clone(), None) &&
+        let result = if Q::cache_on_disk(self, key.clone(), None) &&
                         self.sess.opts.debugging_opts.incremental_queries {
             self.sess.profiler(|p| p.incremental_load_result_start(Q::NAME));
-            let result = Q::try_load_from_disk(self.global_tcx(), prev_dep_node_index);
+            let result = Q::try_load_from_disk(self, prev_dep_node_index);
             self.sess.profiler(|p| p.incremental_load_result_end(Q::NAME));
 
             // We always expect to find a cached result for things that
@@ -643,7 +643,7 @@ impl<'tcx> TyCtxt<'tcx> {
 macro_rules! handle_cycle_error {
     ([][$tcx: expr, $error:expr]) => {{
         $tcx.report_cycle($error).emit();
-        Value::from_cycle_error($tcx.global_tcx())
+        Value::from_cycle_error($tcx)
     }};
     ([fatal_cycle$(, $modifiers:ident)*][$tcx:expr, $error:expr]) => {{
         $tcx.report_cycle($error).emit();
@@ -652,7 +652,7 @@ macro_rules! handle_cycle_error {
     }};
     ([cycle_delay_bug$(, $modifiers:ident)*][$tcx:expr, $error:expr]) => {{
         $tcx.report_cycle($error).delay_as_bug();
-        Value::from_cycle_error($tcx.global_tcx())
+        Value::from_cycle_error($tcx)
     }};
     ([$other:ident$(, $modifiers:ident)*][$($args:tt)*]) => {
         handle_cycle_error!([$($modifiers),*][$($args)*])
@@ -999,7 +999,7 @@ macro_rules! define_queries_inner {
                         // would be missing appropriate entries in `providers`.
                         .unwrap_or(&tcx.queries.fallback_extern_providers)
                         .$name;
-                    provider(tcx.global_tcx(), key)
+                    provider(tcx, key)
                 })
             }
 
diff --git a/src/librustc_macros/src/query.rs b/src/librustc_macros/src/query.rs
index a8df7e197a8c9..9a68dd0f5e3ce 100644
--- a/src/librustc_macros/src/query.rs
+++ b/src/librustc_macros/src/query.rs
@@ -442,8 +442,8 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
                                          .map(|c| c.is_green())
                                          .unwrap_or(false));
 
-                        let key = RecoverKey::recover(tcx.global_tcx(), self).unwrap();
-                        if queries::#name::cache_on_disk(tcx.global_tcx(), key, None) {
+                        let key = RecoverKey::recover(tcx, self).unwrap();
+                        if queries::#name::cache_on_disk(tcx, key, None) {
                             let _ = tcx.#name(key);
                         }
                     }
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 067ab080713c4..d469b9209958f 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -621,7 +621,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx
                 target: _,
                 unwind: _,
             } => {
-                let gcx = self.infcx.tcx.global_tcx();
+                let tcx = self.infcx.tcx;
 
                 // Compute the type with accurate region information.
                 let drop_place_ty = drop_place.ty(self.body, self.infcx.tcx);
@@ -629,10 +629,10 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx
                 // Erase the regions.
                 let drop_place_ty = self.infcx.tcx.erase_regions(&drop_place_ty).ty;
 
-                // "Lift" into the gcx -- once regions are erased, this type should be in the
+                // "Lift" into the tcx -- once regions are erased, this type should be in the
                 // global arenas; this "lift" operation basically just asserts that is true, but
                 // that is useful later.
-                gcx.lift_to_global(&drop_place_ty).unwrap();
+                tcx.lift_to_global(&drop_place_ty).unwrap();
 
                 debug!("visit_terminator_drop \
                         loc: {:?} term: {:?} drop_place: {:?} drop_place_ty: {:?} span: {:?}",
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index e3e509799c936..b981c76905c14 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -1894,9 +1894,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         // Erase the regions from `ty` to get a global type.  The
         // `Sized` bound in no way depends on precise regions, so this
         // shouldn't affect `is_sized`.
-        let gcx = tcx.global_tcx();
         let erased_ty = tcx.erase_regions(&ty);
-        if !erased_ty.is_sized(gcx.at(span), self.param_env) {
+        if !erased_ty.is_sized(tcx.at(span), self.param_env) {
             // in current MIR construction, all non-control-flow rvalue
             // expressions evaluate through `as_temp` or `into` a return
             // slot or local, so to find all unsized rvalues it is enough
diff --git a/src/librustc_mir/borrow_check/nll/universal_regions.rs b/src/librustc_mir/borrow_check/nll/universal_regions.rs
index b5af97a2217e8..9f9450188fa94 100644
--- a/src/librustc_mir/borrow_check/nll/universal_regions.rs
+++ b/src/librustc_mir/borrow_check/nll/universal_regions.rs
@@ -521,9 +521,8 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
         defining_ty: DefiningTy<'tcx>,
     ) -> UniversalRegionIndices<'tcx> {
         let tcx = self.infcx.tcx;
-        let gcx = tcx.global_tcx();
         let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id);
-        let identity_substs = InternalSubsts::identity_for_item(gcx, closure_base_def_id);
+        let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
         let fr_substs = match defining_ty {
             DefiningTy::Closure(_, ClosureSubsts { ref substs })
             | DefiningTy::Generator(_, GeneratorSubsts { ref substs }, _) => {
@@ -542,7 +541,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
             DefiningTy::FnDef(_, substs) | DefiningTy::Const(_, substs) => substs,
         };
 
-        let global_mapping = iter::once((gcx.lifetimes.re_static, fr_static));
+        let global_mapping = iter::once((tcx.lifetimes.re_static, fr_static));
         let subst_mapping = identity_substs
             .regions()
             .zip(fr_substs.regions().map(|r| r.to_region_vid()));
diff --git a/src/librustc_mir/dataflow/drop_flag_effects.rs b/src/librustc_mir/dataflow/drop_flag_effects.rs
index 51b717b69e9c1..0fe58c07b1b86 100644
--- a/src/librustc_mir/dataflow/drop_flag_effects.rs
+++ b/src/librustc_mir/dataflow/drop_flag_effects.rs
@@ -148,9 +148,8 @@ pub(crate) fn on_all_drop_children_bits<'tcx, F>(
         let ty = place.ty(body, tcx).ty;
         debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, place, ty);
 
-        let gcx = tcx.global_tcx();
         let erased_ty = tcx.erase_regions(&ty);
-        if erased_ty.needs_drop(gcx, ctxt.param_env) {
+        if erased_ty.needs_drop(tcx, ctxt.param_env) {
             each_child(child);
         } else {
             debug!("on_all_drop_children_bits - skipping")
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index da1b9ed7693e6..eed51cdab8c3c 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -543,9 +543,9 @@ fn make_mirror_unadjusted<'a, 'tcx>(
         // Now comes the rote stuff:
         hir::ExprKind::Repeat(ref v, ref count) => {
             let def_id = cx.tcx.hir().local_def_id(count.hir_id);
-            let substs = InternalSubsts::identity_for_item(cx.tcx.global_tcx(), def_id);
+            let substs = InternalSubsts::identity_for_item(cx.tcx, def_id);
             let instance = ty::Instance::resolve(
-                cx.tcx.global_tcx(),
+                cx.tcx,
                 cx.param_env,
                 def_id,
                 substs,
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index f7cd29f2e67ef..32efbd6f01173 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -83,7 +83,7 @@ impl<'a, 'tcx> Cx<'a, 'tcx> {
             infcx,
             root_lint_level: src_id,
             param_env: tcx.param_env(src_def_id),
-            identity_substs: InternalSubsts::identity_for_item(tcx.global_tcx(), src_def_id),
+            identity_substs: InternalSubsts::identity_for_item(tcx, src_def_id),
             region_scope_tree: tcx.region_scope_tree(src_def_id),
             tables,
             constness,
@@ -154,12 +154,11 @@ impl<'a, 'tcx> Cx<'a, 'tcx> {
     }
 
     pub fn pattern_from_hir(&mut self, p: &hir::Pat) -> Pat<'tcx> {
-        let tcx = self.tcx.global_tcx();
-        let p = match tcx.hir().get(p.hir_id) {
+        let p = match self.tcx.hir().get(p.hir_id) {
             Node::Pat(p) | Node::Binding(p) => p,
             node => bug!("pattern became {:?}", node)
         };
-        Pat::from_hir(tcx, self.param_env.and(self.identity_substs), self.tables(), p)
+        Pat::from_hir(self.tcx, self.param_env.and(self.identity_substs), self.tables(), p)
     }
 
     pub fn trait_method(&mut self,
@@ -187,7 +186,7 @@ impl<'a, 'tcx> Cx<'a, 'tcx> {
     }
 
     pub fn needs_drop(&mut self, ty: Ty<'tcx>) -> bool {
-        ty.needs_drop(self.tcx.global_tcx(), self.param_env)
+        ty.needs_drop(self.tcx, self.param_env)
     }
 
     pub fn tcx(&self) -> TyCtxt<'tcx> {
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index f5eb07882fe32..4fae0976ffb5a 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -79,7 +79,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx
         }
         ty::InstanceDef::ClosureOnceShim { call_once } => {
             let fn_mut = tcx.lang_items().fn_mut_trait().unwrap();
-            let call_mut = tcx.global_tcx()
+            let call_mut = tcx
                 .associated_items(fn_mut)
                 .find(|it| it.kind == ty::AssocKind::Method)
                 .unwrap().def_id;
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 6f1d854481a10..d08064e6892cd 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1269,7 +1269,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         // to avoid ICEs.
         for item in &regular_traits {
             let object_safety_violations =
-                tcx.global_tcx().astconv_object_safety_violations(item.trait_ref().def_id());
+                tcx.astconv_object_safety_violations(item.trait_ref().def_id());
             if !object_safety_violations.is_empty() {
                 tcx.report_object_safety_error(
                     span,
diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index 58f41ca4f88f9..3403e8b8c890e 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -932,9 +932,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             Ok(self.to_const(count, tcx.type_of(count_def_id)))
         } else {
             let param_env = ty::ParamEnv::empty();
-            let substs = InternalSubsts::identity_for_item(tcx.global_tcx(), count_def_id);
+            let substs = InternalSubsts::identity_for_item(tcx, count_def_id);
             let instance = ty::Instance::resolve(
-                tcx.global_tcx(),
+                tcx,
                 param_env,
                 count_def_id,
                 substs,
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index f4ba9fc03d3d0..7cd3c01904730 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -48,7 +48,7 @@ impl<'tcx> CheckWfFcxBuilder<'tcx> {
                 // empty `param_env`.
                 check_false_global_bounds(&fcx, span, id);
             }
-            let wf_tys = f(&fcx, fcx.tcx.global_tcx());
+            let wf_tys = f(&fcx, fcx.tcx);
             fcx.select_all_obligations_or_error();
             fcx.regionck_item(id, span, &wf_tys);
         });

From f226ab4ad97fbc2e183d319616f17998c66f64e8 Mon Sep 17 00:00:00 2001
From: Mark Rousskov <mark.simulacrum@gmail.com>
Date: Wed, 25 Sep 2019 15:40:21 -0400
Subject: [PATCH 21/24] Remove lift_to_global

---
 src/librustc/mir/mod.rs                  | 2 +-
 src/librustc/ty/context.rs               | 5 -----
 src/librustc/ty/error.rs                 | 2 +-
 src/librustc/ty/print/pretty.rs          | 2 +-
 src/librustc_mir/borrow_check/mod.rs     | 2 +-
 src/librustc_traits/chalk_context/mod.rs | 2 +-
 6 files changed, 5 insertions(+), 10 deletions(-)

diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 967d16fa0d902..cf82184ab032c 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -1504,7 +1504,7 @@ impl<'tcx> TerminatorKind<'tcx> {
             Goto { .. } => vec!["".into()],
             SwitchInt { ref values, switch_ty, .. } => ty::tls::with(|tcx| {
                 let param_env = ty::ParamEnv::empty();
-                let switch_ty = tcx.lift_to_global(&switch_ty).unwrap();
+                let switch_ty = tcx.lift(&switch_ty).unwrap();
                 let size = tcx.layout_of(param_env.and(switch_ty)).unwrap().size;
                 values
                     .iter()
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 2d68ad7fbd5c1..5986388679fb8 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -1148,11 +1148,6 @@ impl<'tcx> TyCtxt<'tcx> {
         value.lift_to_tcx(self)
     }
 
-    /// Like lift, but only tries in the global tcx.
-    pub fn lift_to_global<T: ?Sized + Lift<'tcx>>(self, value: &T) -> Option<T::Lifted> {
-        value.lift_to_tcx(self)
-    }
-
     /// Creates a type context and call the closure with a `TyCtxt` reference
     /// to the context. The closure enforces that the type context and any interned
     /// value (types, substs, etc.) can only be used while `ty::tls` has a valid
diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs
index d12039de3136e..5851a48a8d377 100644
--- a/src/librustc/ty/error.rs
+++ b/src/librustc/ty/error.rs
@@ -193,7 +193,7 @@ impl<'tcx> ty::TyS<'tcx> {
             ty::Adt(def, _) => format!("{} `{}`", def.descr(), tcx.def_path_str(def.did)).into(),
             ty::Foreign(def_id) => format!("extern type `{}`", tcx.def_path_str(def_id)).into(),
             ty::Array(_, n) => {
-                let n = tcx.lift_to_global(&n).unwrap();
+                let n = tcx.lift(&n).unwrap();
                 match n.try_eval_usize(tcx, ty::ParamEnv::empty()) {
                     Some(n) => {
                         format!("array of {} element{}", n, pluralise!(n)).into()
diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index 2bc87d6b8ba5e..e004fa07f2c0f 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -917,7 +917,7 @@ pub trait PrettyPrinter<'tcx>:
                     let min = 1u128 << (bit_size - 1);
                     let max = min - 1;
 
-                    let ty = self.tcx().lift_to_global(&ct.ty).unwrap();
+                    let ty = self.tcx().lift(&ct.ty).unwrap();
                     let size = self.tcx().layout_of(ty::ParamEnv::empty().and(ty))
                         .unwrap()
                         .size;
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index d469b9209958f..d3448b28c1491 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -632,7 +632,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx
                 // "Lift" into the tcx -- once regions are erased, this type should be in the
                 // global arenas; this "lift" operation basically just asserts that is true, but
                 // that is useful later.
-                tcx.lift_to_global(&drop_place_ty).unwrap();
+                tcx.lift(&drop_place_ty).unwrap();
 
                 debug!("visit_terminator_drop \
                         loc: {:?} term: {:?} drop_place: {:?} drop_place_ty: {:?} span: {:?}",
diff --git a/src/librustc_traits/chalk_context/mod.rs b/src/librustc_traits/chalk_context/mod.rs
index 06c1df70287c9..54d580ec05d71 100644
--- a/src/librustc_traits/chalk_context/mod.rs
+++ b/src/librustc_traits/chalk_context/mod.rs
@@ -474,7 +474,7 @@ impl context::UnificationOps<ChalkArenas<'tcx>, ChalkArenas<'tcx>>
         &self,
         value: DelayedLiteral<ChalkArenas<'tcx>>,
     ) -> DelayedLiteral<ChalkArenas<'tcx>> {
-        match self.infcx.tcx.lift_to_global(&value) {
+        match self.infcx.tcx.lift(&value) {
             Some(literal) => literal,
             None => bug!("cannot lift {:?}", value),
         }

From 0a4d55ddb89521899da2d1b6bf047ce01386595e Mon Sep 17 00:00:00 2001
From: Mark Rousskov <mark.simulacrum@gmail.com>
Date: Wed, 25 Sep 2019 16:35:19 -0400
Subject: [PATCH 22/24] Remove stray uses of gcx name

---
 src/librustc/traits/query/type_op/mod.rs |  2 +-
 src/librustc_typeck/check/wfcheck.rs     |  4 +-
 src/librustc_typeck/coherence/builtin.rs | 48 ++++++++++++------------
 3 files changed, 27 insertions(+), 27 deletions(-)

diff --git a/src/librustc/traits/query/type_op/mod.rs b/src/librustc/traits/query/type_op/mod.rs
index e2a5cd9670e0c..989c4aeea0964 100644
--- a/src/librustc/traits/query/type_op/mod.rs
+++ b/src/librustc/traits/query/type_op/mod.rs
@@ -66,7 +66,7 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Sized + TypeFoldable<'tcx> + 'tcx {
         canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>,
     ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self::QueryResponse>>;
 
-    /// Casts a lifted query result (which is in the gcx lifetime)
+    /// Casts a lifted query result (which is in the tcx lifetime)
     /// into the tcx lifetime. This is always just an identity cast,
     /// but the generic code doesn't realize it -- put another way, in
     /// the generic code, we have a `Lifted<'tcx, Self::QueryResponse>`
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 7cd3c01904730..20c517d779b42 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -366,8 +366,8 @@ fn check_item_type(
 ) {
     debug!("check_item_type: {:?}", item_id);
 
-    for_id(tcx, item_id, ty_span).with_fcx(|fcx, gcx| {
-        let ty = gcx.type_of(gcx.hir().local_def_id(item_id));
+    for_id(tcx, item_id, ty_span).with_fcx(|fcx, tcx| {
+        let ty = tcx.type_of(tcx.hir().local_def_id(item_id));
         let item_ty = fcx.normalize_associated_types_in(ty_span, &ty);
 
         let mut forbid_unsized = true;
diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs
index 64bd144dfa226..1e3939cbfcdf2 100644
--- a/src/librustc_typeck/coherence/builtin.rs
+++ b/src/librustc_typeck/coherence/builtin.rs
@@ -322,29 +322,29 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: DefId) {
     }
 }
 
-pub fn coerce_unsized_info<'tcx>(gcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedInfo {
+pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedInfo {
     debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);
-    let coerce_unsized_trait = gcx.lang_items().coerce_unsized_trait().unwrap();
+    let coerce_unsized_trait = tcx.lang_items().coerce_unsized_trait().unwrap();
 
-    let unsize_trait = gcx.lang_items().require(UnsizeTraitLangItem).unwrap_or_else(|err| {
-        gcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err));
+    let unsize_trait = tcx.lang_items().require(UnsizeTraitLangItem).unwrap_or_else(|err| {
+        tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err));
     });
 
     // this provider should only get invoked for local def-ids
-    let impl_hir_id = gcx.hir().as_local_hir_id(impl_did).unwrap_or_else(|| {
+    let impl_hir_id = tcx.hir().as_local_hir_id(impl_did).unwrap_or_else(|| {
         bug!("coerce_unsized_info: invoked for non-local def-id {:?}", impl_did)
     });
 
-    let source = gcx.type_of(impl_did);
-    let trait_ref = gcx.impl_trait_ref(impl_did).unwrap();
+    let source = tcx.type_of(impl_did);
+    let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
     assert_eq!(trait_ref.def_id, coerce_unsized_trait);
     let target = trait_ref.substs.type_at(1);
     debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)",
            source,
            target);
 
-    let span = gcx.hir().span(impl_hir_id);
-    let param_env = gcx.param_env(impl_did);
+    let span = tcx.hir().span(impl_hir_id);
+    let param_env = tcx.param_env(impl_did);
     assert!(!source.has_escaping_bound_vars());
 
     let err_info = CoerceUnsizedInfo { custom_kind: None };
@@ -353,7 +353,7 @@ pub fn coerce_unsized_info<'tcx>(gcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
            source,
            target);
 
-    gcx.infer_ctxt().enter(|infcx| {
+    tcx.infer_ctxt().enter(|infcx| {
         let cause = ObligationCause::misc(span, impl_hir_id);
         let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
                            mt_b: ty::TypeAndMut<'tcx>,
@@ -372,24 +372,24 @@ pub fn coerce_unsized_info<'tcx>(gcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
                 infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a);
                 let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
                 let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
-                check_mutbl(mt_a, mt_b, &|ty| gcx.mk_imm_ref(r_b, ty))
+                check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty))
             }
 
             (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(mt_b)) => {
                 let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
-                check_mutbl(mt_a, mt_b, &|ty| gcx.mk_imm_ptr(ty))
+                check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty))
             }
 
             (&ty::RawPtr(mt_a), &ty::RawPtr(mt_b)) => {
-                check_mutbl(mt_a, mt_b, &|ty| gcx.mk_imm_ptr(ty))
+                check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty))
             }
 
             (&ty::Adt(def_a, substs_a), &ty::Adt(def_b, substs_b)) if def_a.is_struct() &&
                                                                       def_b.is_struct() => {
                 if def_a != def_b {
-                    let source_path = gcx.def_path_str(def_a.did);
-                    let target_path = gcx.def_path_str(def_b.did);
-                    span_err!(gcx.sess,
+                    let source_path = tcx.def_path_str(def_a.did);
+                    let target_path = tcx.def_path_str(def_b.did);
+                    span_err!(tcx.sess,
                               span,
                               E0377,
                               "the trait `CoerceUnsized` may only be implemented \
@@ -443,9 +443,9 @@ pub fn coerce_unsized_info<'tcx>(gcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
                 let diff_fields = fields.iter()
                     .enumerate()
                     .filter_map(|(i, f)| {
-                        let (a, b) = (f.ty(gcx, substs_a), f.ty(gcx, substs_b));
+                        let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b));
 
-                        if gcx.type_of(f.did).is_phantom_data() {
+                        if tcx.type_of(f.did).is_phantom_data() {
                             // Ignore PhantomData fields
                             return None;
                         }
@@ -472,7 +472,7 @@ pub fn coerce_unsized_info<'tcx>(gcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
                     .collect::<Vec<_>>();
 
                 if diff_fields.is_empty() {
-                    span_err!(gcx.sess,
+                    span_err!(tcx.sess,
                               span,
                               E0374,
                               "the trait `CoerceUnsized` may only be implemented \
@@ -480,14 +480,14 @@ pub fn coerce_unsized_info<'tcx>(gcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
                                being coerced, none found");
                     return err_info;
                 } else if diff_fields.len() > 1 {
-                    let item = gcx.hir().expect_item(impl_hir_id);
+                    let item = tcx.hir().expect_item(impl_hir_id);
                     let span = if let ItemKind::Impl(.., Some(ref t), _, _) = item.kind {
                         t.path.span
                     } else {
-                        gcx.hir().span(impl_hir_id)
+                        tcx.hir().span(impl_hir_id)
                     };
 
-                    let mut err = struct_span_err!(gcx.sess,
+                    let mut err = struct_span_err!(tcx.sess,
                                                    span,
                                                    E0375,
                                                    "implementing the trait \
@@ -514,7 +514,7 @@ pub fn coerce_unsized_info<'tcx>(gcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
             }
 
             _ => {
-                span_err!(gcx.sess,
+                span_err!(tcx.sess,
                           span,
                           E0376,
                           "the trait `CoerceUnsized` may only be implemented \
@@ -527,7 +527,7 @@ pub fn coerce_unsized_info<'tcx>(gcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
 
         // Register an obligation for `A: Trait<B>`.
         let cause = traits::ObligationCause::misc(span, impl_hir_id);
-        let predicate = gcx.predicate_for_trait_def(param_env,
+        let predicate = tcx.predicate_for_trait_def(param_env,
                                                     cause,
                                                     trait_def_id,
                                                     0,

From 4b23503b4285f7dd9ee92fd267b3cafaa723a048 Mon Sep 17 00:00:00 2001
From: Mark Rousskov <mark.simulacrum@gmail.com>
Date: Wed, 25 Sep 2019 16:40:24 -0400
Subject: [PATCH 23/24] Remove shrink_to_tcx_lifetime

There's no longer two distinct gcx and tcx lifetimes which made this
necessary (or, at least, the code compiles -- it's possible we got
better at normalizing, but that seems unlikely).
---
 .../traits/query/type_op/ascribe_user_type.rs |  8 +---
 src/librustc/traits/query/type_op/eq.rs       |  8 +---
 .../query/type_op/implied_outlives_bounds.rs  |  8 +---
 src/librustc/traits/query/type_op/mod.rs      | 21 +---------
 .../traits/query/type_op/normalize.rs         | 38 +------------------
 src/librustc/traits/query/type_op/outlives.rs |  8 +---
 .../traits/query/type_op/prove_predicate.rs   |  8 +---
 src/librustc/traits/query/type_op/subtype.rs  |  8 +---
 8 files changed, 9 insertions(+), 98 deletions(-)

diff --git a/src/librustc/traits/query/type_op/ascribe_user_type.rs b/src/librustc/traits/query/type_op/ascribe_user_type.rs
index 05a4d4336a7c2..34aa4ee78da30 100644
--- a/src/librustc/traits/query/type_op/ascribe_user_type.rs
+++ b/src/librustc/traits/query/type_op/ascribe_user_type.rs
@@ -1,4 +1,4 @@
-use crate::infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse};
+use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
 use crate::traits::query::Fallible;
 use crate::hir::def_id::DefId;
 use crate::ty::{ParamEnvAnd, Ty, TyCtxt};
@@ -37,12 +37,6 @@ impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> {
     ) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> {
         tcx.type_op_ascribe_user_type(canonicalized)
     }
-
-    fn shrink_to_tcx_lifetime(
-        v: &'a CanonicalizedQueryResponse<'tcx, ()>,
-    ) -> &'a Canonical<'tcx, QueryResponse<'tcx, ()>> {
-        v
-    }
 }
 
 BraceStructTypeFoldableImpl! {
diff --git a/src/librustc/traits/query/type_op/eq.rs b/src/librustc/traits/query/type_op/eq.rs
index e8ec304f918a3..3653f9268dcde 100644
--- a/src/librustc/traits/query/type_op/eq.rs
+++ b/src/librustc/traits/query/type_op/eq.rs
@@ -1,4 +1,4 @@
-use crate::infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse};
+use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
 use crate::traits::query::Fallible;
 use crate::ty::{ParamEnvAnd, Ty, TyCtxt};
 
@@ -34,12 +34,6 @@ impl<'tcx> super::QueryTypeOp<'tcx> for Eq<'tcx> {
     ) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> {
         tcx.type_op_eq(canonicalized)
     }
-
-    fn shrink_to_tcx_lifetime(
-        v: &'a CanonicalizedQueryResponse<'tcx, ()>,
-    ) -> &'a Canonical<'tcx, QueryResponse<'tcx, ()>> {
-        v
-    }
 }
 
 BraceStructTypeFoldableImpl! {
diff --git a/src/librustc/traits/query/type_op/implied_outlives_bounds.rs b/src/librustc/traits/query/type_op/implied_outlives_bounds.rs
index 3beb4d64656c5..12a834fbda6bd 100644
--- a/src/librustc/traits/query/type_op/implied_outlives_bounds.rs
+++ b/src/librustc/traits/query/type_op/implied_outlives_bounds.rs
@@ -1,4 +1,4 @@
-use crate::infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse};
+use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
 use crate::traits::query::outlives_bounds::OutlivesBound;
 use crate::traits::query::Fallible;
 use crate::ty::{ParamEnvAnd, Ty, TyCtxt};
@@ -38,12 +38,6 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> {
 
         tcx.implied_outlives_bounds(canonicalized)
     }
-
-    fn shrink_to_tcx_lifetime(
-        v: &'a CanonicalizedQueryResponse<'tcx, Self::QueryResponse>,
-    ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self::QueryResponse>> {
-        v
-    }
 }
 
 BraceStructTypeFoldableImpl! {
diff --git a/src/librustc/traits/query/type_op/mod.rs b/src/librustc/traits/query/type_op/mod.rs
index 989c4aeea0964..98e535234b630 100644
--- a/src/librustc/traits/query/type_op/mod.rs
+++ b/src/librustc/traits/query/type_op/mod.rs
@@ -1,6 +1,6 @@
 use crate::infer::canonical::{
-    Canonical, Canonicalized, CanonicalizedQueryResponse, OriginalQueryValues,
-    QueryRegionConstraints, QueryResponse,
+    Canonicalized, CanonicalizedQueryResponse, OriginalQueryValues,
+    QueryRegionConstraints,
 };
 use crate::infer::{InferCtxt, InferOk};
 use std::fmt;
@@ -66,22 +66,6 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Sized + TypeFoldable<'tcx> + 'tcx {
         canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>,
     ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self::QueryResponse>>;
 
-    /// Casts a lifted query result (which is in the tcx lifetime)
-    /// into the tcx lifetime. This is always just an identity cast,
-    /// but the generic code doesn't realize it -- put another way, in
-    /// the generic code, we have a `Lifted<'tcx, Self::QueryResponse>`
-    /// and we want to convert that to a `Self::QueryResponse`. This is
-    /// not a priori valid, so we can't do it -- but in practice, it
-    /// is always a no-op (e.g., the lifted form of a type,
-    /// `Ty<'tcx>`, is a subtype of `Ty<'tcx>`). So we have to push
-    /// the operation into the impls that know more specifically what
-    /// `QueryResponse` is. This operation would (maybe) be nicer with
-    /// something like HKTs or GATs, since then we could make
-    /// `QueryResponse` parametric and `'tcx` and `'tcx` etc.
-    fn shrink_to_tcx_lifetime(
-        lifted_query_result: &'a CanonicalizedQueryResponse<'tcx, Self::QueryResponse>,
-    ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self::QueryResponse>>;
-
     fn fully_perform_into(
         query_key: ParamEnvAnd<'tcx, Self>,
         infcx: &InferCtxt<'_, 'tcx>,
@@ -99,7 +83,6 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Sized + TypeFoldable<'tcx> + 'tcx {
         let canonical_self =
             infcx.canonicalize_hr_query_hack(&query_key, &mut canonical_var_values);
         let canonical_result = Self::perform_query(infcx.tcx, canonical_self)?;
-        let canonical_result = Self::shrink_to_tcx_lifetime(&canonical_result);
 
         let param_env = query_key.param_env;
 
diff --git a/src/librustc/traits/query/type_op/normalize.rs b/src/librustc/traits/query/type_op/normalize.rs
index 3fe85d8d83eb9..2138f792d45bb 100644
--- a/src/librustc/traits/query/type_op/normalize.rs
+++ b/src/librustc/traits/query/type_op/normalize.rs
@@ -1,4 +1,4 @@
-use crate::infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse};
+use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
 use std::fmt;
 use crate::traits::query::Fallible;
 use crate::ty::fold::TypeFoldable;
@@ -38,12 +38,6 @@ where
     ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self::QueryResponse>> {
         T::type_op_method(tcx, canonicalized)
     }
-
-    fn shrink_to_tcx_lifetime(
-        v: &'a CanonicalizedQueryResponse<'tcx, T>,
-    ) -> &'a Canonical<'tcx, QueryResponse<'tcx, T>> {
-        T::shrink_to_tcx_lifetime(v)
-    }
 }
 
 pub trait Normalizable<'tcx>: fmt::Debug + TypeFoldable<'tcx> + Lift<'tcx> + Copy {
@@ -51,12 +45,6 @@ pub trait Normalizable<'tcx>: fmt::Debug + TypeFoldable<'tcx> + Lift<'tcx> + Cop
         tcx: TyCtxt<'tcx>,
         canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
     ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>>;
-
-    /// Converts from the `'tcx` (lifted) form of `Self` into the `tcx`
-    /// form of `Self`.
-    fn shrink_to_tcx_lifetime(
-        v: &'a CanonicalizedQueryResponse<'tcx, Self>,
-    ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self>>;
 }
 
 impl Normalizable<'tcx> for Ty<'tcx> {
@@ -66,12 +54,6 @@ impl Normalizable<'tcx> for Ty<'tcx> {
     ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>> {
         tcx.type_op_normalize_ty(canonicalized)
     }
-
-    fn shrink_to_tcx_lifetime(
-        v: &'a CanonicalizedQueryResponse<'tcx, Self>,
-    ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self>> {
-        v
-    }
 }
 
 impl Normalizable<'tcx> for ty::Predicate<'tcx> {
@@ -81,12 +63,6 @@ impl Normalizable<'tcx> for ty::Predicate<'tcx> {
     ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>> {
         tcx.type_op_normalize_predicate(canonicalized)
     }
-
-    fn shrink_to_tcx_lifetime(
-        v: &'a CanonicalizedQueryResponse<'tcx, Self>,
-    ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self>> {
-        v
-    }
 }
 
 impl Normalizable<'tcx> for ty::PolyFnSig<'tcx> {
@@ -96,12 +72,6 @@ impl Normalizable<'tcx> for ty::PolyFnSig<'tcx> {
     ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>> {
         tcx.type_op_normalize_poly_fn_sig(canonicalized)
     }
-
-    fn shrink_to_tcx_lifetime(
-        v: &'a CanonicalizedQueryResponse<'tcx, Self>,
-    ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self>> {
-        v
-    }
 }
 
 impl Normalizable<'tcx> for ty::FnSig<'tcx> {
@@ -111,12 +81,6 @@ impl Normalizable<'tcx> for ty::FnSig<'tcx> {
     ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>> {
         tcx.type_op_normalize_fn_sig(canonicalized)
     }
-
-    fn shrink_to_tcx_lifetime(
-        v: &'a CanonicalizedQueryResponse<'tcx, Self>,
-    ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self>> {
-        v
-    }
 }
 
 BraceStructTypeFoldableImpl! {
diff --git a/src/librustc/traits/query/type_op/outlives.rs b/src/librustc/traits/query/type_op/outlives.rs
index d4b36356ffb06..9b956f3e55408 100644
--- a/src/librustc/traits/query/type_op/outlives.rs
+++ b/src/librustc/traits/query/type_op/outlives.rs
@@ -1,4 +1,4 @@
-use crate::infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse};
+use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
 use crate::traits::query::dropck_outlives::trivial_dropck_outlives;
 use crate::traits::query::dropck_outlives::DropckOutlivesResult;
 use crate::traits::query::Fallible;
@@ -53,12 +53,6 @@ impl super::QueryTypeOp<'tcx> for DropckOutlives<'tcx> {
 
         tcx.dropck_outlives(canonicalized)
     }
-
-    fn shrink_to_tcx_lifetime(
-        lifted_query_result: &'a CanonicalizedQueryResponse<'tcx, Self::QueryResponse>,
-    ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self::QueryResponse>> {
-        lifted_query_result
-    }
 }
 
 BraceStructTypeFoldableImpl! {
diff --git a/src/librustc/traits/query/type_op/prove_predicate.rs b/src/librustc/traits/query/type_op/prove_predicate.rs
index 1efe66326d724..2a908d0f66e5b 100644
--- a/src/librustc/traits/query/type_op/prove_predicate.rs
+++ b/src/librustc/traits/query/type_op/prove_predicate.rs
@@ -1,4 +1,4 @@
-use crate::infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse};
+use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
 use crate::traits::query::Fallible;
 use crate::ty::{ParamEnvAnd, Predicate, TyCtxt};
 
@@ -43,12 +43,6 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> {
     ) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> {
         tcx.type_op_prove_predicate(canonicalized)
     }
-
-    fn shrink_to_tcx_lifetime(
-        v: &'a CanonicalizedQueryResponse<'tcx, ()>,
-    ) -> &'a Canonical<'tcx, QueryResponse<'tcx, ()>> {
-        v
-    }
 }
 
 BraceStructTypeFoldableImpl! {
diff --git a/src/librustc/traits/query/type_op/subtype.rs b/src/librustc/traits/query/type_op/subtype.rs
index 71c74999c2762..c89a55daa095e 100644
--- a/src/librustc/traits/query/type_op/subtype.rs
+++ b/src/librustc/traits/query/type_op/subtype.rs
@@ -1,4 +1,4 @@
-use crate::infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse};
+use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
 use crate::traits::query::Fallible;
 use crate::ty::{ParamEnvAnd, Ty, TyCtxt};
 
@@ -34,12 +34,6 @@ impl<'tcx> super::QueryTypeOp<'tcx> for Subtype<'tcx> {
     ) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> {
         tcx.type_op_subtype(canonicalized)
     }
-
-    fn shrink_to_tcx_lifetime(
-        v: &'a CanonicalizedQueryResponse<'tcx, ()>,
-    ) -> &'a Canonical<'tcx, QueryResponse<'tcx, ()>> {
-        v
-    }
 }
 
 BraceStructTypeFoldableImpl! {

From 6ccb7ae6438c0da774d75752cbf7cb68f2a622be Mon Sep 17 00:00:00 2001
From: Andre Bogus <bogusandre@gmail.com>
Date: Mon, 23 Sep 2019 09:28:31 +0200
Subject: [PATCH 24/24] Docs: slice elements are equidistant

---
 src/libstd/primitive_docs.rs | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs
index 45816ffd229f0..02f664760c08c 100644
--- a/src/libstd/primitive_docs.rs
+++ b/src/libstd/primitive_docs.rs
@@ -566,7 +566,9 @@ mod prim_array { }
 #[doc(alias = "[")]
 #[doc(alias = "]")]
 #[doc(alias = "[]")]
-/// A dynamically-sized view into a contiguous sequence, `[T]`.
+/// A dynamically-sized view into a contiguous sequence, `[T]`. Contiguous here
+/// means that elements are layed out so that every element is the same
+/// distance from its neighbors.
 ///
 /// *[See also the `std::slice` module](slice/index.html).*
 ///