about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-04-02 13:06:12 +0000
committerbors <bors@rust-lang.org>2019-04-02 13:06:12 +0000
commite008e4fde837313d4a72da603ef492a721afc998 (patch)
tree75b10cd677718373adfa76658ae592bb8fac39ad
parentf694222887cf31f51e68927716c25736e62f037f (diff)
parentd0d34663375f32f766aa290fa201fdc72ce7ddcf (diff)
downloadrust-e008e4fde837313d4a72da603ef492a721afc998.tar.gz
rust-e008e4fde837313d4a72da603ef492a721afc998.zip
Auto merge of #59632 - Centril:rollup, r=Centril
Rollup of 8 pull requests

Successful merges:

 - #59262 (Remove duplicated code from Iterator::{ne, lt, le, gt, ge})
 - #59286 (Refactor async fn return type lowering)
 - #59444 (Implement useful steps_between for all integers)
 - #59452 (Speed up rustdoc run a bit)
 - #59533 (Support allocating iterators with arenas)
 - #59585 (Fixes for shallow borrows)
 - #59607 (Renames `EvalErrorKind` to `InterpError`)
 - #59613 (SGX target: convert a bunch of panics to aborts)

Failed merges:

 - #59630 (Shrink `mir::Statement`.)

r? @ghost
-rw-r--r--Cargo.lock7
-rw-r--r--src/libarena/Cargo.toml1
-rw-r--r--src/libarena/lib.rs155
-rw-r--r--src/libcore/benches/iter.rs10
-rw-r--r--src/libcore/iter/range.rs61
-rw-r--r--src/libcore/iter/traits/iterator.rs112
-rw-r--r--src/libcore/tests/iter.rs61
-rw-r--r--src/librustc/hir/intravisit.rs6
-rw-r--r--src/librustc/hir/lowering.rs661
-rw-r--r--src/librustc/hir/mod.rs12
-rw-r--r--src/librustc/infer/opaque_types/mod.rs80
-rw-r--r--src/librustc/middle/resolve_lifetime.rs2
-rw-r--r--src/librustc/mir/interpret/error.rs30
-rw-r--r--src/librustc/mir/interpret/mod.rs4
-rw-r--r--src/librustc/mir/mod.rs8
-rw-r--r--src/librustc/mir/visit.rs2
-rw-r--r--src/librustc_codegen_ssa/mir/block.rs6
-rw-r--r--src/librustc_mir/borrow_check/error_reporting.rs8
-rw-r--r--src/librustc_mir/borrow_check/mod.rs2
-rw-r--r--src/librustc_mir/borrow_check/nll/invalidation.rs2
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs2
-rw-r--r--src/librustc_mir/build/expr/as_place.rs2
-rw-r--r--src/librustc_mir/build/expr/as_rvalue.rs10
-rw-r--r--src/librustc_mir/const_eval.rs8
-rw-r--r--src/librustc_mir/interpret/cast.rs4
-rw-r--r--src/librustc_mir/interpret/eval_context.rs12
-rw-r--r--src/librustc_mir/interpret/intrinsics.rs8
-rw-r--r--src/librustc_mir/interpret/memory.rs8
-rw-r--r--src/librustc_mir/interpret/operand.rs6
-rw-r--r--src/librustc_mir/interpret/snapshot.rs4
-rw-r--r--src/librustc_mir/interpret/terminator.rs6
-rw-r--r--src/librustc_mir/interpret/validity.rs12
-rw-r--r--src/librustc_mir/transform/const_prop.rs8
-rw-r--r--src/librustc_mir/transform/generator.rs2
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs5
-rw-r--r--src/librustc_typeck/collect.rs1
-rw-r--r--src/librustdoc/Cargo.toml2
-rw-r--r--src/librustdoc/html/render.rs85
-rw-r--r--src/libstd/sys/sgx/abi/mod.rs6
-rw-r--r--src/libstd/sys/sgx/abi/reloc.rs2
-rw-r--r--src/libstd/sys/sgx/abi/tls.rs10
-rw-r--r--src/libstd/sys/sgx/abi/usercalls/alloc.rs8
-rw-r--r--src/libstd/sys/sgx/abi/usercalls/mod.rs4
-rw-r--r--src/libstd/sys/sgx/abi/usercalls/raw.rs29
-rw-r--r--src/libstd/sys/sgx/condvar.rs5
-rw-r--r--src/libstd/sys/sgx/mod.rs2
-rw-r--r--src/libstd/sys/sgx/rwlock.rs2
-rw-r--r--src/libstd/sys/sgx/thread.rs14
-rw-r--r--src/libstd/sys/sgx/waitqueue.rs18
-rw-r--r--src/libstd/sys_common/mod.rs9
-rw-r--r--src/test/mir-opt/match_false_edges.rs4
-rw-r--r--src/test/run-pass/async-await.rs20
-rw-r--r--src/test/ui/async-fn-multiple-lifetimes.rs5
-rw-r--r--src/test/ui/async-fn-multiple-lifetimes.stderr34
-rw-r--r--src/test/ui/issues/issue-54974.rs16
-rw-r--r--src/test/ui/issues/issue-55324.rs14
-rw-r--r--src/test/ui/issues/issue-58885.rs21
-rw-r--r--src/test/ui/issues/issue-59001.rs17
58 files changed, 982 insertions, 673 deletions
diff --git a/Cargo.lock b/Cargo.lock
index c071a2e11d2..c7007017078 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -54,6 +54,7 @@ name = "arena"
 version = "0.0.0"
 dependencies = [
  "rustc_data_structures 0.0.0",
+ "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -1520,7 +1521,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "minifier"
-version = "0.0.28"
+version = "0.0.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "macro-utils 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3039,7 +3040,7 @@ dependencies = [
 name = "rustdoc"
 version = "0.0.0"
 dependencies = [
- "minifier 0.0.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "minifier 0.0.29 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -4149,7 +4150,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0a3eb002f0535929f1199681417029ebea04aadc0c7a4224b46be99c7f5d6a16"
 "checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff"
 "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
-"checksum minifier 0.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "3a2898502751dcc9d66b6fff57f3cf63cc91605e83e1a33515396f5027f8e4ca"
+"checksum minifier 0.0.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1f4950cb2617b1933e2da0446e864dfe0d6a22c22ff72297996c46e6a63b210b"
 "checksum miniz-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0300eafb20369952951699b68243ab4334f4b10a88f411c221d444b36c40e649"
 "checksum miniz_oxide 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ad30a47319c16cde58d0314f5d98202a80c9083b5f61178457403dfb14e509c"
 "checksum miniz_oxide_c_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "28edaef377517fd9fe3e085c37d892ce7acd1fbeab9239c5a36eec352d8a8b7e"
diff --git a/src/libarena/Cargo.toml b/src/libarena/Cargo.toml
index 82fc64ba64e..aa1bf38b995 100644
--- a/src/libarena/Cargo.toml
+++ b/src/libarena/Cargo.toml
@@ -11,3 +11,4 @@ crate-type = ["dylib"]
 
 [dependencies]
 rustc_data_structures = { path = "../librustc_data_structures" }
+smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs
index 8ae046c0796..0a5b79c36aa 100644
--- a/src/libarena/lib.rs
+++ b/src/libarena/lib.rs
@@ -23,7 +23,9 @@
 
 extern crate alloc;
 
+use rustc_data_structures::cold_path;
 use rustc_data_structures::sync::MTLock;
+use smallvec::SmallVec;
 
 use std::cell::{Cell, RefCell};
 use std::cmp;
@@ -55,6 +57,8 @@ pub struct TypedArena<T> {
 struct TypedArenaChunk<T> {
     /// The raw storage for the arena chunk.
     storage: RawVec<T>,
+    /// The number of valid entries in the chunk.
+    entries: usize,
 }
 
 impl<T> TypedArenaChunk<T> {
@@ -62,6 +66,7 @@ impl<T> TypedArenaChunk<T> {
     unsafe fn new(capacity: usize) -> TypedArenaChunk<T> {
         TypedArenaChunk {
             storage: RawVec::with_capacity(capacity),
+            entries: 0,
         }
     }
 
@@ -149,6 +154,34 @@ impl<T> TypedArena<T> {
         }
     }
 
+    #[inline]
+    fn can_allocate(&self, len: usize) -> bool {
+        let available_capacity_bytes = self.end.get() as usize - self.ptr.get() as usize;
+        let at_least_bytes = len.checked_mul(mem::size_of::<T>()).unwrap();
+        available_capacity_bytes >= at_least_bytes
+    }
+
+    /// Ensures there's enough space in the current chunk to fit `len` objects.
+    #[inline]
+    fn ensure_capacity(&self, len: usize) {
+        if !self.can_allocate(len) {
+            self.grow(len);
+            debug_assert!(self.can_allocate(len));
+        }
+    }
+
+    #[inline]
+    unsafe fn alloc_raw_slice(&self, len: usize) -> *mut T {
+        assert!(mem::size_of::<T>() != 0);
+        assert!(len != 0);
+
+        self.ensure_capacity(len);
+
+        let start_ptr = self.ptr.get();
+        self.ptr.set(start_ptr.add(len));
+        start_ptr
+    }
+
     /// Allocates a slice of objects that are copied into the `TypedArena`, returning a mutable
     /// reference to it. Will panic if passed a zero-sized types.
     ///
@@ -161,21 +194,64 @@ impl<T> TypedArena<T> {
     where
         T: Copy,
     {
+        unsafe {
+            let len = slice.len();
+            let start_ptr = self.alloc_raw_slice(len);
+            slice.as_ptr().copy_to_nonoverlapping(start_ptr, len);
+            slice::from_raw_parts_mut(start_ptr, len)
+        }
+    }
+
+    #[inline]
+    pub fn alloc_from_iter<I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T] {
         assert!(mem::size_of::<T>() != 0);
-        assert!(slice.len() != 0);
+        let mut iter = iter.into_iter();
+        let size_hint = iter.size_hint();
 
-        let available_capacity_bytes = self.end.get() as usize - self.ptr.get() as usize;
-        let at_least_bytes = slice.len() * mem::size_of::<T>();
-        if available_capacity_bytes < at_least_bytes {
-            self.grow(slice.len());
-        }
+        match size_hint {
+            (min, Some(max)) if min == max => {
+                // We know the exact number of elements the iterator will produce here
+                let len = min;
 
-        unsafe {
-            let start_ptr = self.ptr.get();
-            let arena_slice = slice::from_raw_parts_mut(start_ptr, slice.len());
-            self.ptr.set(start_ptr.add(arena_slice.len()));
-            arena_slice.copy_from_slice(slice);
-            arena_slice
+                if len == 0 {
+                    return &mut [];
+                }
+
+                self.ensure_capacity(len);
+
+                let slice = self.ptr.get();
+
+                unsafe {
+                    let mut ptr = self.ptr.get();
+                    for _ in 0..len {
+                        // Write into uninitialized memory.
+                        ptr::write(ptr, iter.next().unwrap());
+                        // Advance the pointer.
+                        ptr = ptr.offset(1);
+                        // Update the pointer per iteration so if `iter.next()` panics
+                        // we destroy the correct amount
+                        self.ptr.set(ptr);
+                    }
+                    slice::from_raw_parts_mut(slice, len)
+                }
+            }
+            _ => {
+                cold_path(move || -> &mut [T] {
+                    let mut vec: SmallVec<[_; 8]> = iter.collect();
+                    if vec.is_empty() {
+                        return &mut [];
+                    }
+                    // Move the content to the arena by copying it and then forgetting
+                    // the content of the SmallVec
+                    unsafe {
+                        let len = vec.len();
+                        let start_ptr = self.alloc_raw_slice(len);
+                        vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
+                        vec.set_len(0);
+                        slice::from_raw_parts_mut(start_ptr, len)
+                    }
+                })
+            }
         }
     }
 
@@ -189,6 +265,7 @@ impl<T> TypedArena<T> {
             if let Some(last_chunk) = chunks.last_mut() {
                 let used_bytes = self.ptr.get() as usize - last_chunk.start() as usize;
                 let currently_used_cap = used_bytes / mem::size_of::<T>();
+                last_chunk.entries = currently_used_cap;
                 if last_chunk.storage.reserve_in_place(currently_used_cap, n) {
                     self.end.set(last_chunk.end());
                     return;
@@ -222,8 +299,7 @@ impl<T> TypedArena<T> {
                 let len = chunks_borrow.len();
                 // If `T` is ZST, code below has no effect.
                 for mut chunk in chunks_borrow.drain(..len-1) {
-                    let cap = chunk.storage.cap();
-                    chunk.destroy(cap);
+                    chunk.destroy(chunk.entries);
                 }
             }
         }
@@ -265,8 +341,7 @@ unsafe impl<#[may_dangle] T> Drop for TypedArena<T> {
                 self.clear_last_chunk(&mut last_chunk);
                 // The last chunk will be dropped. Destroy all other chunks.
                 for chunk in chunks_borrow.iter_mut() {
-                    let cap = chunk.storage.cap();
-                    chunk.destroy(cap);
+                    chunk.destroy(chunk.entries);
                 }
             }
             // RawVec handles deallocation of `last_chunk` and `self.chunks`.
@@ -410,6 +485,54 @@ impl DroplessArena {
             arena_slice
         }
     }
+
+    #[inline]
+    pub fn alloc_from_iter<T, I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T] {
+        let mut iter = iter.into_iter();
+        assert!(mem::size_of::<T>() != 0);
+        assert!(!mem::needs_drop::<T>());
+
+        let size_hint = iter.size_hint();
+
+        match size_hint {
+            (min, Some(max)) if min == max => {
+                // We know the exact number of elements the iterator will produce here
+                let len = min;
+
+                if len == 0 {
+                    return &mut []
+                }
+                let size = len.checked_mul(mem::size_of::<T>()).unwrap();
+                let mem = self.alloc_raw(size, mem::align_of::<T>()) as *mut _ as *mut T;
+                unsafe {
+                    for i in 0..len {
+                        ptr::write(mem.offset(i as isize), iter.next().unwrap())
+                    }
+                    slice::from_raw_parts_mut(mem, len)
+                }
+            }
+            (_, _) => {
+                cold_path(move || -> &mut [T] {
+                    let mut vec: SmallVec<[_; 8]> = iter.collect();
+                    if vec.is_empty() {
+                        return &mut [];
+                    }
+                    // Move the content to the arena by copying it and then forgetting
+                    // the content of the SmallVec
+                    unsafe {
+                        let len = vec.len();
+                        let start_ptr = self.alloc_raw(
+                            len * mem::size_of::<T>(),
+                            mem::align_of::<T>()
+                        ) as *mut _ as *mut T;
+                        vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
+                        vec.set_len(0);
+                        slice::from_raw_parts_mut(start_ptr, len)
+                    }
+                })
+            }
+        }
+    }
 }
 
 #[derive(Default)]
diff --git a/src/libcore/benches/iter.rs b/src/libcore/benches/iter.rs
index 825bd368bdf..7dcfad8306f 100644
--- a/src/libcore/benches/iter.rs
+++ b/src/libcore/benches/iter.rs
@@ -334,3 +334,13 @@ fn bench_filter_chain_ref_count(b: &mut Bencher) {
         (0i64..1000000).chain(0..1000000).map(black_box).by_ref().filter(|x| x % 3 == 0).count()
     })
 }
+
+#[bench]
+fn bench_partial_cmp(b: &mut Bencher) {
+    b.iter(|| (0..100000).map(black_box).partial_cmp((0..100000).map(black_box)))
+}
+
+#[bench]
+fn bench_lt(b: &mut Bencher) {
+    b.iter(|| (0..100000).map(black_box).lt((0..100000).map(black_box)))
+}
diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs
index e7efd9728b9..aefed1890fe 100644
--- a/src/libcore/iter/range.rs
+++ b/src/libcore/iter/range.rs
@@ -68,11 +68,9 @@ macro_rules! step_impl_unsigned {
                    issue = "42168")]
         impl Step for $t {
             #[inline]
-            #[allow(trivial_numeric_casts)]
             fn steps_between(start: &$t, end: &$t) -> Option<usize> {
                 if *start < *end {
-                    // Note: We assume $t <= usize here
-                    Some((*end - *start) as usize)
+                    usize::try_from(*end - *start).ok()
                 } else {
                     Some(0)
                 }
@@ -98,13 +96,11 @@ macro_rules! step_impl_signed {
                    issue = "42168")]
         impl Step for $t {
             #[inline]
-            #[allow(trivial_numeric_casts)]
             fn steps_between(start: &$t, end: &$t) -> Option<usize> {
                 if *start < *end {
-                    // Note: We assume $t <= isize here
-                    // Use .wrapping_sub and cast to usize to compute the
-                    // difference that may not fit inside the range of isize.
-                    Some((*end as isize).wrapping_sub(*start as isize) as usize)
+                    // Use .wrapping_sub and cast to unsigned to compute the
+                    // difference that may not fit inside the range of $t.
+                    usize::try_from(end.wrapping_sub(*start) as $unsigned).ok()
                 } else {
                     Some(0)
                 }
@@ -134,46 +130,9 @@ macro_rules! step_impl_signed {
     )*)
 }
 
-macro_rules! step_impl_no_between {
-    ($($t:ty)*) => ($(
-        #[unstable(feature = "step_trait",
-                   reason = "likely to be replaced by finer-grained traits",
-                   issue = "42168")]
-        impl Step for $t {
-            #[inline]
-            fn steps_between(_start: &Self, _end: &Self) -> Option<usize> {
-                None
-            }
-
-            #[inline]
-            fn add_usize(&self, n: usize) -> Option<Self> {
-                self.checked_add(n as $t)
-            }
-
-            step_identical_methods!();
-        }
-    )*)
-}
-
-step_impl_unsigned!(usize u8 u16);
-#[cfg(not(target_pointer_width = "16"))]
-step_impl_unsigned!(u32);
-#[cfg(target_pointer_width = "16")]
-step_impl_no_between!(u32);
+step_impl_unsigned!(usize u8 u16 u32 u64 u128);
 step_impl_signed!([isize: usize] [i8: u8] [i16: u16]);
-#[cfg(not(target_pointer_width = "16"))]
-step_impl_signed!([i32: u32]);
-#[cfg(target_pointer_width = "16")]
-step_impl_no_between!(i32);
-#[cfg(target_pointer_width = "64")]
-step_impl_unsigned!(u64);
-#[cfg(target_pointer_width = "64")]
-step_impl_signed!([i64: u64]);
-// If the target pointer width is not 64-bits, we
-// assume here that it is less than 64-bits.
-#[cfg(not(target_pointer_width = "64"))]
-step_impl_no_between!(u64 i64);
-step_impl_no_between!(u128 i128);
+step_impl_signed!([i32: u32] [i64: u64] [i128: u128]);
 
 macro_rules! range_exact_iter_impl {
     ($($t:ty)*) => ($(
@@ -229,7 +188,7 @@ impl<A: Step> Iterator for ops::Range<A> {
     fn size_hint(&self) -> (usize, Option<usize>) {
         match Step::steps_between(&self.start, &self.end) {
             Some(hint) => (hint, Some(hint)),
-            None => (0, None)
+            None => (usize::MAX, None)
         }
     }
 
@@ -273,8 +232,8 @@ range_incl_exact_iter_impl!(u8 u16 i8 i16);
 //
 // They need to guarantee that .size_hint() is either exact, or that
 // the upper bound is None when it does not fit the type limits.
-range_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 i64 u64);
-range_incl_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 i64 u64);
+range_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 u64 i64 u128 i128);
+range_incl_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 u64 i64 u128 i128);
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<A: Step> DoubleEndedIterator for ops::Range<A> {
@@ -350,7 +309,7 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
 
         match Step::steps_between(&self.start, &self.end) {
             Some(hint) => (hint.saturating_add(1), hint.checked_add(1)),
-            None => (0, None),
+            None => (usize::MAX, None),
         }
     }
 
diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs
index ca7feed0712..6df4a457655 100644
--- a/src/libcore/iter/traits/iterator.rs
+++ b/src/libcore/iter/traits/iterator.rs
@@ -2435,145 +2435,61 @@ pub trait Iterator {
     /// Determines if the elements of this `Iterator` are unequal to those of
     /// another.
     #[stable(feature = "iter_order", since = "1.5.0")]
-    fn ne<I>(mut self, other: I) -> bool where
+    fn ne<I>(self, other: I) -> bool where
         I: IntoIterator,
         Self::Item: PartialEq<I::Item>,
         Self: Sized,
     {
-        let mut other = other.into_iter();
-
-        loop {
-            let x = match self.next() {
-                None => return other.next().is_some(),
-                Some(val) => val,
-            };
-
-            let y = match other.next() {
-                None => return true,
-                Some(val) => val,
-            };
-
-            if x != y { return true }
-        }
+        !self.eq(other)
     }
 
     /// Determines if the elements of this `Iterator` are lexicographically
     /// less than those of another.
     #[stable(feature = "iter_order", since = "1.5.0")]
-    fn lt<I>(mut self, other: I) -> bool where
+    fn lt<I>(self, other: I) -> bool where
         I: IntoIterator,
         Self::Item: PartialOrd<I::Item>,
         Self: Sized,
     {
-        let mut other = other.into_iter();
-
-        loop {
-            let x = match self.next() {
-                None => return other.next().is_some(),
-                Some(val) => val,
-            };
-
-            let y = match other.next() {
-                None => return false,
-                Some(val) => val,
-            };
-
-            match x.partial_cmp(&y) {
-                Some(Ordering::Less) => return true,
-                Some(Ordering::Equal) => (),
-                Some(Ordering::Greater) => return false,
-                None => return false,
-            }
-        }
+        self.partial_cmp(other) == Some(Ordering::Less)
     }
 
     /// Determines if the elements of this `Iterator` are lexicographically
     /// less or equal to those of another.
     #[stable(feature = "iter_order", since = "1.5.0")]
-    fn le<I>(mut self, other: I) -> bool where
+    fn le<I>(self, other: I) -> bool where
         I: IntoIterator,
         Self::Item: PartialOrd<I::Item>,
         Self: Sized,
     {
-        let mut other = other.into_iter();
-
-        loop {
-            let x = match self.next() {
-                None => { other.next(); return true; },
-                Some(val) => val,
-            };
-
-            let y = match other.next() {
-                None => return false,
-                Some(val) => val,
-            };
-
-            match x.partial_cmp(&y) {
-                Some(Ordering::Less) => return true,
-                Some(Ordering::Equal) => (),
-                Some(Ordering::Greater) => return false,
-                None => return false,
-            }
+        match self.partial_cmp(other) {
+            Some(Ordering::Less) | Some(Ordering::Equal) => true,
+            _ => false,
         }
     }
 
     /// Determines if the elements of this `Iterator` are lexicographically
     /// greater than those of another.
     #[stable(feature = "iter_order", since = "1.5.0")]
-    fn gt<I>(mut self, other: I) -> bool where
+    fn gt<I>(self, other: I) -> bool where
         I: IntoIterator,
         Self::Item: PartialOrd<I::Item>,
         Self: Sized,
     {
-        let mut other = other.into_iter();
-
-        loop {
-            let x = match self.next() {
-                None => { other.next(); return false; },
-                Some(val) => val,
-            };
-
-            let y = match other.next() {
-                None => return true,
-                Some(val) => val,
-            };
-
-            match x.partial_cmp(&y) {
-                Some(Ordering::Less) => return false,
-                Some(Ordering::Equal) => (),
-                Some(Ordering::Greater) => return true,
-                None => return false,
-            }
-        }
+        self.partial_cmp(other) == Some(Ordering::Greater)
     }
 
     /// Determines if the elements of this `Iterator` are lexicographically
     /// greater than or equal to those of another.
     #[stable(feature = "iter_order", since = "1.5.0")]
-    fn ge<I>(mut self, other: I) -> bool where
+    fn ge<I>(self, other: I) -> bool where
         I: IntoIterator,
         Self::Item: PartialOrd<I::Item>,
         Self: Sized,
     {
-        let mut other = other.into_iter();
-
-        loop {
-            let x = match self.next() {
-                None => return other.next().is_none(),
-                Some(val) => val,
-            };
-
-            let y = match other.next() {
-                None => return true,
-                Some(val) => val,
-            };
-
-            match x.partial_cmp(&y) {
-                Some(Ordering::Less) => return false,
-                Some(Ordering::Equal) => (),
-                Some(Ordering::Greater) => return true,
-                None => return false,
-            }
+        match self.partial_cmp(other) {
+            Some(Ordering::Greater) | Some(Ordering::Equal) => true,
+            _ => false,
         }
     }
 
diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs
index a3f0b02e2fe..d5b581d336d 100644
--- a/src/libcore/tests/iter.rs
+++ b/src/libcore/tests/iter.rs
@@ -1,4 +1,5 @@
 use core::cell::Cell;
+use core::convert::TryFrom;
 use core::iter::*;
 use core::{i8, i16, isize};
 use core::usize;
@@ -1801,6 +1802,66 @@ fn test_range_inclusive_folds() {
 }
 
 #[test]
+fn test_range_size_hint() {
+    use core::usize::MAX as UMAX;
+    assert_eq!((0..0usize).size_hint(), (0, Some(0)));
+    assert_eq!((0..100usize).size_hint(), (100, Some(100)));
+    assert_eq!((0..UMAX).size_hint(), (UMAX, Some(UMAX)));
+
+    let umax = u128::try_from(UMAX).unwrap();
+    assert_eq!((0..0u128).size_hint(), (0, Some(0)));
+    assert_eq!((0..100u128).size_hint(), (100, Some(100)));
+    assert_eq!((0..umax).size_hint(), (UMAX, Some(UMAX)));
+    assert_eq!((0..umax + 1).size_hint(), (UMAX, None));
+
+    use core::isize::{MAX as IMAX, MIN as IMIN};
+    assert_eq!((0..0isize).size_hint(), (0, Some(0)));
+    assert_eq!((-100..100isize).size_hint(), (200, Some(200)));
+    assert_eq!((IMIN..IMAX).size_hint(), (UMAX, Some(UMAX)));
+
+    let imin = i128::try_from(IMIN).unwrap();
+    let imax = i128::try_from(IMAX).unwrap();
+    assert_eq!((0..0i128).size_hint(), (0, Some(0)));
+    assert_eq!((-100..100i128).size_hint(), (200, Some(200)));
+    assert_eq!((imin..imax).size_hint(), (UMAX, Some(UMAX)));
+    assert_eq!((imin..imax + 1).size_hint(), (UMAX, None));
+}
+
+#[test]
+fn test_range_inclusive_size_hint() {
+    use core::usize::MAX as UMAX;
+    assert_eq!((1..=0usize).size_hint(), (0, Some(0)));
+    assert_eq!((0..=0usize).size_hint(), (1, Some(1)));
+    assert_eq!((0..=100usize).size_hint(), (101, Some(101)));
+    assert_eq!((0..=UMAX - 1).size_hint(), (UMAX, Some(UMAX)));
+    assert_eq!((0..=UMAX).size_hint(), (UMAX, None));
+
+    let umax = u128::try_from(UMAX).unwrap();
+    assert_eq!((1..=0u128).size_hint(), (0, Some(0)));
+    assert_eq!((0..=0u128).size_hint(), (1, Some(1)));
+    assert_eq!((0..=100u128).size_hint(), (101, Some(101)));
+    assert_eq!((0..=umax - 1).size_hint(), (UMAX, Some(UMAX)));
+    assert_eq!((0..=umax).size_hint(), (UMAX, None));
+    assert_eq!((0..=umax + 1).size_hint(), (UMAX, None));
+
+    use core::isize::{MAX as IMAX, MIN as IMIN};
+    assert_eq!((0..=-1isize).size_hint(), (0, Some(0)));
+    assert_eq!((0..=0isize).size_hint(), (1, Some(1)));
+    assert_eq!((-100..=100isize).size_hint(), (201, Some(201)));
+    assert_eq!((IMIN..=IMAX - 1).size_hint(), (UMAX, Some(UMAX)));
+    assert_eq!((IMIN..=IMAX).size_hint(), (UMAX, None));
+
+    let imin = i128::try_from(IMIN).unwrap();
+    let imax = i128::try_from(IMAX).unwrap();
+    assert_eq!((0..=-1i128).size_hint(), (0, Some(0)));
+    assert_eq!((0..=0i128).size_hint(), (1, Some(1)));
+    assert_eq!((-100..=100i128).size_hint(), (201, Some(201)));
+    assert_eq!((imin..=imax - 1).size_hint(), (UMAX, Some(UMAX)));
+    assert_eq!((imin..=imax).size_hint(), (UMAX, None));
+    assert_eq!((imin..=imax + 1).size_hint(), (UMAX, None));
+}
+
+#[test]
 fn test_repeat() {
     let mut it = repeat(42);
     assert_eq!(it.next(), Some(42));
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 6689b0c26fb..c2265eeb30d 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -490,7 +490,11 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
             visitor.visit_ty(ty);
             visitor.visit_generics(generics)
         }
-        ItemKind::Existential(ExistTy { ref generics, ref bounds, impl_trait_fn: _ }) => {
+        ItemKind::Existential(ExistTy {
+            ref generics,
+            ref bounds,
+            ..
+        }) => {
             visitor.visit_id(item.hir_id);
             walk_generics(visitor, generics);
             walk_list!(visitor, visit_param_bound, bounds);
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 7dfb16602a3..2a255523676 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -66,7 +66,7 @@ use syntax::symbol::{keywords, Symbol};
 use syntax::tokenstream::{TokenStream, TokenTree};
 use syntax::parse::token::Token;
 use syntax::visit::{self, Visitor};
-use syntax_pos::{Span, MultiSpan};
+use syntax_pos::Span;
 
 const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF;
 
@@ -318,6 +318,49 @@ enum AnonymousLifetimeMode {
 
     /// Pass responsibility to `resolve_lifetime` code for all cases.
     PassThrough,
+
+    /// Used in the return types of `async fn` where there exists
+    /// exactly one argument-position elided lifetime.
+    ///
+    /// In `async fn`, we lower the arguments types using the `CreateParameter`
+    /// mode, meaning that non-`dyn` elided lifetimes are assigned a fresh name.
+    /// If any corresponding elided lifetimes appear in the output, we need to
+    /// replace them with references to the fresh name assigned to the corresponding
+    /// elided lifetime in the arguments.
+    ///
+    /// For **Modern cases**, replace the anonymous parameter with a
+    /// reference to a specific freshly-named lifetime that was
+    /// introduced in argument
+    ///
+    /// For **Dyn Bound** cases, pass responsibility to
+    /// `resole_lifetime` code.
+    Replace(LtReplacement),
+}
+
+/// The type of elided lifetime replacement to perform on `async fn` return types.
+#[derive(Copy, Clone)]
+enum LtReplacement {
+    /// Fresh name introduced by the single non-dyn elided lifetime
+    /// in the arguments of the async fn.
+    Some(ParamName),
+
+    /// There is no single non-dyn elided lifetime because no lifetimes
+    /// appeared in the arguments.
+    NoLifetimes,
+
+    /// There is no single non-dyn elided lifetime because multiple
+    /// lifetimes appeared in the arguments.
+    MultipleLifetimes,
+}
+
+/// Calculates the `LtReplacement` to use for elided lifetimes in the return
+/// type based on the fresh elided lifetimes introduced in argument position.
+fn get_elided_lt_replacement(arg_position_lifetimes: &[(Span, ParamName)]) -> LtReplacement {
+    match arg_position_lifetimes {
+        [] => LtReplacement::NoLifetimes,
+        [(_span, param)] => LtReplacement::Some(*param),
+        _ => LtReplacement::MultipleLifetimes,
+    }
 }
 
 struct ImplTraitTypeIdVisitor<'a> { ids: &'a mut SmallVec<[NodeId; 1]> }
@@ -778,53 +821,63 @@ impl<'a> LoweringContext<'a> {
 
         let params = lifetimes_to_define
             .into_iter()
-            .map(|(span, hir_name)| {
-                let LoweredNodeId { node_id, hir_id } = self.next_id();
-
-                // Get the name we'll use to make the def-path. Note
-                // that collisions are ok here and this shouldn't
-                // really show up for end-user.
-                let (str_name, kind) = match hir_name {
-                    ParamName::Plain(ident) => (
-                        ident.as_interned_str(),
-                        hir::LifetimeParamKind::InBand,
-                    ),
-                    ParamName::Fresh(_) => (
-                        keywords::UnderscoreLifetime.name().as_interned_str(),
-                        hir::LifetimeParamKind::Elided,
-                    ),
-                    ParamName::Error => (
-                        keywords::UnderscoreLifetime.name().as_interned_str(),
-                        hir::LifetimeParamKind::Error,
-                    ),
-                };
-
-                // Add a definition for the in-band lifetime def.
-                self.resolver.definitions().create_def_with_parent(
-                    parent_id.index,
-                    node_id,
-                    DefPathData::LifetimeParam(str_name),
-                    DefIndexAddressSpace::High,
-                    Mark::root(),
-                    span,
-                );
-
-                hir::GenericParam {
-                    hir_id,
-                    name: hir_name,
-                    attrs: hir_vec![],
-                    bounds: hir_vec![],
-                    span,
-                    pure_wrt_drop: false,
-                    kind: hir::GenericParamKind::Lifetime { kind }
-                }
-            })
+            .map(|(span, hir_name)| self.lifetime_to_generic_param(
+                span, hir_name, parent_id.index,
+            ))
             .chain(in_band_ty_params.into_iter())
             .collect();
 
         (params, res)
     }
 
+    /// Converts a lifetime into a new generic parameter.
+    fn lifetime_to_generic_param(
+        &mut self,
+        span: Span,
+        hir_name: ParamName,
+        parent_index: DefIndex,
+    ) -> hir::GenericParam {
+        let LoweredNodeId { node_id, hir_id } = self.next_id();
+
+        // Get the name we'll use to make the def-path. Note
+        // that collisions are ok here and this shouldn't
+        // really show up for end-user.
+        let (str_name, kind) = match hir_name {
+            ParamName::Plain(ident) => (
+                ident.as_interned_str(),
+                hir::LifetimeParamKind::InBand,
+            ),
+            ParamName::Fresh(_) => (
+                keywords::UnderscoreLifetime.name().as_interned_str(),
+                hir::LifetimeParamKind::Elided,
+            ),
+            ParamName::Error => (
+                keywords::UnderscoreLifetime.name().as_interned_str(),
+                hir::LifetimeParamKind::Error,
+            ),
+        };
+
+        // Add a definition for the in-band lifetime def.
+        self.resolver.definitions().create_def_with_parent(
+            parent_index,
+            node_id,
+            DefPathData::LifetimeParam(str_name),
+            DefIndexAddressSpace::High,
+            Mark::root(),
+            span,
+        );
+
+        hir::GenericParam {
+            hir_id,
+            name: hir_name,
+            attrs: hir_vec![],
+            bounds: hir_vec![],
+            span,
+            pure_wrt_drop: false,
+            kind: hir::GenericParamKind::Lifetime { kind }
+        }
+    }
+
     /// When there is a reference to some lifetime `'a`, and in-band
     /// lifetimes are enabled, then we want to push that lifetime into
     /// the vector of names to define later. In that case, it will get
@@ -928,6 +981,13 @@ impl<'a> LoweringContext<'a> {
             |this| {
                 this.collect_in_band_defs(parent_id, anonymous_lifetime_mode, |this| {
                     let mut params = Vec::new();
+                    // Note: it is necessary to lower generics *before* calling `f`.
+                    // When lowering `async fn`, there's a final step when lowering
+                    // the return type that assumes that all in-scope lifetimes have
+                    // already been added to either `in_scope_lifetimes` or
+                    // `lifetimes_to_define`. If we swapped the order of these two,
+                    // in-band-lifetimes introduced by generics or where-clauses
+                    // wouldn't have been added yet.
                     let generics = this.lower_generics(
                         generics,
                         ImplTraitContext::Universal(&mut params),
@@ -1426,42 +1486,62 @@ impl<'a> LoweringContext<'a> {
 
         self.with_hir_id_owner(exist_ty_node_id, |lctx| {
             let LoweredNodeId { node_id: _, hir_id } = lctx.next_id();
-            let exist_ty_item_kind = hir::ItemKind::Existential(hir::ExistTy {
+            let exist_ty_item = hir::ExistTy {
                 generics: hir::Generics {
                     params: lifetime_defs,
                     where_clause: hir::WhereClause {
                         hir_id,
-                        predicates: Vec::new().into(),
+                        predicates: hir_vec![],
                     },
                     span,
                 },
                 bounds: hir_bounds,
                 impl_trait_fn: fn_def_id,
-            });
-            let exist_ty_id = lctx.lower_node_id(exist_ty_node_id);
-            // Generate an `existential type Foo: Trait;` declaration.
-            trace!("creating existential type with id {:#?}", exist_ty_id);
-
-            trace!("exist ty def index: {:#?}", exist_ty_def_index);
-            let exist_ty_item = hir::Item {
-                hir_id: exist_ty_id.hir_id,
-                ident: keywords::Invalid.ident(),
-                attrs: Default::default(),
-                node: exist_ty_item_kind,
-                vis: respan(span.shrink_to_lo(), hir::VisibilityKind::Inherited),
-                span: exist_ty_span,
+                origin: hir::ExistTyOrigin::ReturnImplTrait,
             };
 
-            // Insert the item into the global list. This usually happens
-            // automatically for all AST items. But this existential type item
-            // does not actually exist in the AST.
-            lctx.insert_item(exist_ty_item);
+            trace!("exist ty from impl trait def index: {:#?}", exist_ty_def_index);
+            let exist_ty_id = lctx.generate_existential_type(
+                exist_ty_node_id,
+                exist_ty_item,
+                span,
+                exist_ty_span,
+            );
 
             // `impl Trait` now just becomes `Foo<'a, 'b, ..>`.
             hir::TyKind::Def(hir::ItemId { id: exist_ty_id.hir_id }, lifetimes)
         })
     }
 
+    /// Registers a new existential type with the proper NodeIds and
+    /// returns the lowered node ID for the existential type.
+    fn generate_existential_type(
+        &mut self,
+        exist_ty_node_id: NodeId,
+        exist_ty_item: hir::ExistTy,
+        span: Span,
+        exist_ty_span: Span,
+    ) -> LoweredNodeId {
+        let exist_ty_item_kind = hir::ItemKind::Existential(exist_ty_item);
+        let exist_ty_id = self.lower_node_id(exist_ty_node_id);
+        // Generate an `existential type Foo: Trait;` declaration.
+        trace!("registering existential type with id {:#?}", exist_ty_id);
+        let exist_ty_item = hir::Item {
+            hir_id: exist_ty_id.hir_id,
+            ident: keywords::Invalid.ident(),
+            attrs: Default::default(),
+            node: exist_ty_item_kind,
+            vis: respan(span.shrink_to_lo(), hir::VisibilityKind::Inherited),
+            span: exist_ty_span,
+        };
+
+        // Insert the item into the global item list. This usually happens
+        // automatically for all AST items. But this existential type item
+        // does not actually exist in the AST.
+        self.insert_item(exist_ty_item);
+        exist_ty_id
+    }
+
     fn lifetimes_from_impl_trait_bounds(
         &mut self,
         exist_ty_id: NodeId,
@@ -1569,9 +1649,6 @@ impl<'a> LoweringContext<'a> {
                         name,
                     }));
 
-                    // We need to manually create the ids here, because the
-                    // definitions will go into the explicit `existential type`
-                    // declaration and thus need to have their owner set to that item
                     let def_node_id = self.context.sess.next_node_id();
                     let LoweredNodeId { node_id: _, hir_id } =
                         self.context.lower_node_id_with_owner(def_node_id, self.exist_ty_id);
@@ -2108,23 +2185,42 @@ impl<'a> LoweringContext<'a> {
         impl_trait_return_allow: bool,
         make_ret_async: Option<NodeId>,
     ) -> P<hir::FnDecl> {
-        let inputs = decl.inputs
-            .iter()
-            .map(|arg| {
-                if let Some((_, ref mut ibty)) = in_band_ty_params {
-                    self.lower_ty_direct(&arg.ty, ImplTraitContext::Universal(ibty))
-                } else {
-                    self.lower_ty_direct(&arg.ty, ImplTraitContext::disallowed())
-                }
-            })
-            .collect::<HirVec<_>>();
+        let lt_mode = if make_ret_async.is_some() {
+            // In `async fn`, argument-position elided lifetimes
+            // must be transformed into fresh generic parameters so that
+            // they can be applied to the existential return type.
+            AnonymousLifetimeMode::CreateParameter
+        } else {
+            self.anonymous_lifetime_mode
+        };
+
+        // Remember how many lifetimes were already around so that we can
+        // only look at the lifetime parameters introduced by the arguments.
+        let lifetime_count_before_args = self.lifetimes_to_define.len();
+        let inputs = self.with_anonymous_lifetime_mode(lt_mode, |this| {
+            decl.inputs
+                .iter()
+                .map(|arg| {
+                    if let Some((_, ibty)) = &mut in_band_ty_params {
+                        this.lower_ty_direct(&arg.ty, ImplTraitContext::Universal(ibty))
+                    } else {
+                        this.lower_ty_direct(&arg.ty, ImplTraitContext::disallowed())
+                    }
+                })
+                .collect::<HirVec<_>>()
+        });
 
         let output = if let Some(ret_id) = make_ret_async {
+            // Calculate the `LtReplacement` to use for any return-position elided
+            // lifetimes based on the elided lifetime parameters introduced in the args.
+            let lt_replacement = get_elided_lt_replacement(
+                &self.lifetimes_to_define[lifetime_count_before_args..]
+            );
             self.lower_async_fn_ret_ty(
-                &inputs,
                 &decl.output,
                 in_band_ty_params.expect("make_ret_async but no fn_def_id").0,
                 ret_id,
+                lt_replacement,
             )
         } else {
             match decl.output {
@@ -2173,233 +2269,171 @@ impl<'a> LoweringContext<'a> {
         })
     }
 
-    // Transform `-> T` into `-> impl Future<Output = T>` for `async fn`
+    // Transform `-> T` for `async fn` into -> ExistTy { .. }
+    // combined with the following definition of `ExistTy`:
+    //
+    // existential type ExistTy<generics_from_parent_fn>: Future<Output = T>;
     //
-    // fn_span: the span of the async function declaration. Used for error reporting.
     // inputs: lowered types of arguments to the function. Used to collect lifetimes.
     // output: unlowered output type (`T` in `-> T`)
     // fn_def_id: DefId of the parent function. Used to create child impl trait definition.
+    // exist_ty_node_id: NodeId of the existential type that should be created.
+    // elided_lt_replacement: replacement for elided lifetimes in the return type
     fn lower_async_fn_ret_ty(
         &mut self,
-        inputs: &[hir::Ty],
         output: &FunctionRetTy,
         fn_def_id: DefId,
-        return_impl_trait_id: NodeId,
+        exist_ty_node_id: NodeId,
+        elided_lt_replacement: LtReplacement,
     ) -> hir::FunctionRetTy {
-        // Get lifetimes used in the input arguments to the function. Our output type must also
-        // have the same lifetime.
-        // FIXME(cramertj): multiple different lifetimes are not allowed because
-        // `impl Trait + 'a + 'b` doesn't allow for capture `'a` and `'b` where neither is a subset
-        // of the other. We really want some new lifetime that is a subset of all input lifetimes,
-        // but that doesn't exist at the moment.
-
-        struct AsyncFnLifetimeCollector<'r, 'a: 'r> {
-            context: &'r mut LoweringContext<'a>,
-            // Lifetimes bound by HRTB.
-            currently_bound_lifetimes: Vec<hir::LifetimeName>,
-            // Whether to count elided lifetimes.
-            // Disabled inside of `Fn` or `fn` syntax.
-            collect_elided_lifetimes: bool,
-            // The lifetime found.
-            // Multiple different or elided lifetimes cannot appear in async fn for now.
-            output_lifetime: Option<(hir::LifetimeName, Span)>,
-        }
-
-        impl<'r, 'a: 'r, 'v> hir::intravisit::Visitor<'v> for AsyncFnLifetimeCollector<'r, 'a> {
-            fn nested_visit_map<'this>(
-                &'this mut self,
-            ) -> hir::intravisit::NestedVisitorMap<'this, 'v> {
-                hir::intravisit::NestedVisitorMap::None
-            }
+        let span = output.span();
 
-            fn visit_generic_args(&mut self, span: Span, parameters: &'v hir::GenericArgs) {
-                // Don't collect elided lifetimes used inside of `Fn()` syntax.
-                if parameters.parenthesized {
-                    let old_collect_elided_lifetimes = self.collect_elided_lifetimes;
-                    self.collect_elided_lifetimes = false;
-                    hir::intravisit::walk_generic_args(self, span, parameters);
-                    self.collect_elided_lifetimes = old_collect_elided_lifetimes;
-                } else {
-                    hir::intravisit::walk_generic_args(self, span, parameters);
-                }
-            }
-
-            fn visit_ty(&mut self, t: &'v hir::Ty) {
-                // Don't collect elided lifetimes used inside of `fn()` syntax.
-                if let &hir::TyKind::BareFn(_) = &t.node {
-                    let old_collect_elided_lifetimes = self.collect_elided_lifetimes;
-                    self.collect_elided_lifetimes = false;
-
-                    // Record the "stack height" of `for<'a>` lifetime bindings
-                    // to be able to later fully undo their introduction.
-                    let old_len = self.currently_bound_lifetimes.len();
-                    hir::intravisit::walk_ty(self, t);
-                    self.currently_bound_lifetimes.truncate(old_len);
-
-                    self.collect_elided_lifetimes = old_collect_elided_lifetimes;
-                } else {
-                    hir::intravisit::walk_ty(self, t);
-                }
-            }
+        let exist_ty_span = self.mark_span_with_reason(
+            CompilerDesugaringKind::Async,
+            span,
+            None,
+        );
 
-            fn visit_poly_trait_ref(
-                &mut self,
-                trait_ref: &'v hir::PolyTraitRef,
-                modifier: hir::TraitBoundModifier,
-            ) {
-                // Record the "stack height" of `for<'a>` lifetime bindings
-                // to be able to later fully undo their introduction.
-                let old_len = self.currently_bound_lifetimes.len();
-                hir::intravisit::walk_poly_trait_ref(self, trait_ref, modifier);
-                self.currently_bound_lifetimes.truncate(old_len);
-            }
+        let exist_ty_def_index = self
+            .resolver
+            .definitions()
+            .opt_def_index(exist_ty_node_id)
+            .unwrap();
 
-            fn visit_generic_param(&mut self, param: &'v hir::GenericParam) {
-                 // Record the introduction of 'a in `for<'a> ...`
-                if let hir::GenericParamKind::Lifetime { .. } = param.kind {
-                    // Introduce lifetimes one at a time so that we can handle
-                    // cases like `fn foo<'d>() -> impl for<'a, 'b: 'a, 'c: 'b + 'd>`
-                    let lt_name = hir::LifetimeName::Param(param.name);
-                    self.currently_bound_lifetimes.push(lt_name);
-                }
+        self.allocate_hir_id_counter(exist_ty_node_id);
 
-                hir::intravisit::walk_generic_param(self, param);
-            }
+        let (exist_ty_node_id, lifetime_params) = self.with_hir_id_owner(exist_ty_node_id, |this| {
+            let future_bound = this.with_anonymous_lifetime_mode(
+                AnonymousLifetimeMode::Replace(elided_lt_replacement),
+                |this| this.lower_async_fn_output_type_to_future_bound(
+                    output,
+                    fn_def_id,
+                    span,
+                ),
+            );
 
-            fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
-                let name = match lifetime.name {
-                    hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => {
-                        if self.collect_elided_lifetimes {
-                            // Use `'_` for both implicit and underscore lifetimes in
-                            // `abstract type Foo<'_>: SomeTrait<'_>;`
-                            hir::LifetimeName::Underscore
-                        } else {
-                            return;
-                        }
-                    }
-                    hir::LifetimeName::Param(_) => lifetime.name,
-                    hir::LifetimeName::Error | hir::LifetimeName::Static => return,
-                };
+            // Calculate all the lifetimes that should be captured
+            // by the existential type. This should include all in-scope
+            // lifetime parameters, including those defined in-band.
+            //
+            // Note: this must be done after lowering the output type,
+            // as the output type may introduce new in-band lifetimes.
+            let lifetime_params: Vec<(Span, ParamName)> =
+                this.in_scope_lifetimes
+                    .iter().cloned()
+                    .map(|ident| (ident.span, ParamName::Plain(ident)))
+                    .chain(this.lifetimes_to_define.iter().cloned())
+                    .collect();
 
-                if !self.currently_bound_lifetimes.contains(&name) {
-                    if let Some((current_lt_name, current_lt_span)) = self.output_lifetime {
-                        // We don't currently have a reliable way to desugar `async fn` with
-                        // multiple potentially unrelated input lifetimes into
-                        // `-> impl Trait + 'lt`, so we report an error in this case.
-                        if current_lt_name != name {
-                            struct_span_err!(
-                                self.context.sess,
-                                MultiSpan::from_spans(vec![current_lt_span, lifetime.span]),
-                                E0709,
-                                "multiple different lifetimes used in arguments of `async fn`",
-                            )
-                                .span_label(current_lt_span, "first lifetime here")
-                                .span_label(lifetime.span, "different lifetime here")
-                                .help("`async fn` can only accept borrowed values \
-                                      with identical lifetimes")
-                                .emit()
-                        } else if current_lt_name.is_elided() && name.is_elided() {
-                            struct_span_err!(
-                                self.context.sess,
-                                MultiSpan::from_spans(vec![current_lt_span, lifetime.span]),
-                                E0707,
-                                "multiple elided lifetimes used in arguments of `async fn`",
-                            )
-                                .span_label(current_lt_span, "first lifetime here")
-                                .span_label(lifetime.span, "different lifetime here")
-                                .help("consider giving these arguments named lifetimes")
-                                .emit()
-                        }
-                    } else {
-                        self.output_lifetime = Some((name, lifetime.span));
-                    }
-                }
-            }
-        }
+            let generic_params =
+                lifetime_params
+                    .iter().cloned()
+                    .map(|(span, hir_name)| {
+                        this.lifetime_to_generic_param(span, hir_name, exist_ty_def_index)
+                    })
+                    .collect();
 
-        let bound_lifetime = {
-            let mut lifetime_collector = AsyncFnLifetimeCollector {
-                context: self,
-                currently_bound_lifetimes: Vec::new(),
-                collect_elided_lifetimes: true,
-                output_lifetime: None,
+            let LoweredNodeId { node_id: _, hir_id } = this.next_id();
+            let exist_ty_item = hir::ExistTy {
+                generics: hir::Generics {
+                    params: generic_params,
+                    where_clause: hir::WhereClause {
+                        hir_id,
+                        predicates: hir_vec![],
+                    },
+                    span,
+                },
+                bounds: hir_vec![future_bound],
+                impl_trait_fn: Some(fn_def_id),
+                origin: hir::ExistTyOrigin::AsyncFn,
             };
 
-            for arg in inputs {
-                hir::intravisit::walk_ty(&mut lifetime_collector, arg);
-            }
-            lifetime_collector.output_lifetime
-        };
+            trace!("exist ty from async fn def index: {:#?}", exist_ty_def_index);
+            let exist_ty_id = this.generate_existential_type(
+                exist_ty_node_id,
+                exist_ty_item,
+                span,
+                exist_ty_span,
+            );
 
-        let span = match output {
-            FunctionRetTy::Ty(ty) => ty.span,
-            FunctionRetTy::Default(span) => *span,
-        };
+            (exist_ty_id.node_id, lifetime_params)
+        });
 
-        let impl_trait_ty = self.lower_existential_impl_trait(
-            span, Some(fn_def_id), return_impl_trait_id, |this| {
-            let output_ty = match output {
-                FunctionRetTy::Ty(ty) => {
-                    this.lower_ty(ty, ImplTraitContext::Existential(Some(fn_def_id)))
-                }
-                FunctionRetTy::Default(span) => {
-                    let LoweredNodeId { node_id: _, hir_id } = this.next_id();
-                    P(hir::Ty {
+        let generic_args =
+            lifetime_params
+                .iter().cloned()
+                .map(|(span, hir_name)| {
+                    let LoweredNodeId { node_id: _, hir_id  } = self.next_id();
+                    GenericArg::Lifetime(hir::Lifetime {
                         hir_id,
-                        node: hir::TyKind::Tup(hir_vec![]),
-                        span: *span,
+                        span,
+                        name: hir::LifetimeName::Param(hir_name),
                     })
-                }
-            };
-
-            // "<Output = T>"
-            let LoweredNodeId { node_id: _, hir_id } = this.next_id();
-            let future_params = P(hir::GenericArgs {
-                args: hir_vec![],
-                bindings: hir_vec![hir::TypeBinding {
-                    ident: Ident::from_str(FN_OUTPUT_NAME),
-                    ty: output_ty,
-                    hir_id,
-                    span,
-                }],
-                parenthesized: false,
-            });
+                })
+                .collect();
 
-            let future_path =
-                this.std_path(span, &["future", "Future"], Some(future_params), false);
+        let exist_ty_hir_id = self.lower_node_id(exist_ty_node_id).hir_id;
+        let exist_ty_ref = hir::TyKind::Def(hir::ItemId { id: exist_ty_hir_id }, generic_args);
 
-            let LoweredNodeId { node_id: _, hir_id } = this.next_id();
-            let mut bounds = vec![
-                hir::GenericBound::Trait(
-                    hir::PolyTraitRef {
-                        trait_ref: hir::TraitRef {
-                            path: future_path,
-                            hir_ref_id: hir_id,
-                        },
-                        bound_generic_params: hir_vec![],
-                        span,
-                    },
-                    hir::TraitBoundModifier::None
-                ),
-            ];
+        let LoweredNodeId { node_id: _, hir_id } = self.next_id();
+        hir::FunctionRetTy::Return(P(hir::Ty {
+            node: exist_ty_ref,
+            span,
+            hir_id,
+        }))
+    }
 
-            if let Some((name, span)) = bound_lifetime {
-                let LoweredNodeId { node_id: _, hir_id } = this.next_id();
-                bounds.push(hir::GenericBound::Outlives(
-                    hir::Lifetime { hir_id, name, span }));
+    /// Turns `-> T` into `Future<Output = T>`
+    fn lower_async_fn_output_type_to_future_bound(
+        &mut self,
+        output: &FunctionRetTy,
+        fn_def_id: DefId,
+        span: Span,
+    ) -> hir::GenericBound {
+        // Compute the `T` in `Future<Output = T>` from the return type.
+        let output_ty = match output {
+            FunctionRetTy::Ty(ty) => {
+                self.lower_ty(ty, ImplTraitContext::Existential(Some(fn_def_id)))
             }
+            FunctionRetTy::Default(ret_ty_span) => {
+                let LoweredNodeId { node_id: _, hir_id } = self.next_id();
+                P(hir::Ty {
+                    hir_id,
+                    node: hir::TyKind::Tup(hir_vec![]),
+                    span: *ret_ty_span,
+                })
+            }
+        };
 
-            hir::HirVec::from(bounds)
-        });
-
+        // "<Output = T>"
         let LoweredNodeId { node_id: _, hir_id } = self.next_id();
-        let impl_trait_ty = P(hir::Ty {
-            node: impl_trait_ty,
-            span,
-            hir_id,
+        let future_params = P(hir::GenericArgs {
+            args: hir_vec![],
+            bindings: hir_vec![hir::TypeBinding {
+                ident: Ident::from_str(FN_OUTPUT_NAME),
+                ty: output_ty,
+                hir_id,
+                span,
+            }],
+            parenthesized: false,
         });
 
-        hir::FunctionRetTy::Return(impl_trait_ty)
+        // ::std::future::Future<future_params>
+        let future_path =
+            self.std_path(span, &["future", "Future"], Some(future_params), false);
+
+        let LoweredNodeId { node_id: _, hir_id } = self.next_id();
+        hir::GenericBound::Trait(
+            hir::PolyTraitRef {
+                trait_ref: hir::TraitRef {
+                    path: future_path,
+                    hir_ref_id: hir_id,
+                },
+                bound_generic_params: hir_vec![],
+                span,
+            },
+            hir::TraitBoundModifier::None,
+        )
     }
 
     fn lower_param_bound(
@@ -2437,6 +2471,11 @@ impl<'a> LoweringContext<'a> {
                     }
 
                     AnonymousLifetimeMode::ReportError => self.new_error_lifetime(Some(l.id), span),
+
+                    AnonymousLifetimeMode::Replace(replacement) => {
+                        let LoweredNodeId { node_id: _, hir_id  } = self.lower_node_id(l.id);
+                        self.replace_elided_lifetime(hir_id, span, replacement)
+                    }
                 },
             ident => {
                 self.maybe_collect_in_band_lifetime(ident);
@@ -2461,6 +2500,39 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
+    /// Replace a return-position elided lifetime with the elided lifetime
+    /// from the arguments.
+    fn replace_elided_lifetime(
+        &mut self,
+        hir_id: hir::HirId,
+        span: Span,
+        replacement: LtReplacement,
+    ) -> hir::Lifetime {
+        let multiple_or_none = match replacement {
+            LtReplacement::Some(name) => {
+                return hir::Lifetime {
+                    hir_id,
+                    span,
+                    name: hir::LifetimeName::Param(name),
+                };
+            }
+            LtReplacement::MultipleLifetimes => "multiple",
+            LtReplacement::NoLifetimes => "none",
+        };
+
+        let mut err = crate::middle::resolve_lifetime::report_missing_lifetime_specifiers(
+            self.sess,
+            span,
+            1,
+        );
+        err.note(&format!(
+            "return-position elided lifetimes require exactly one \
+             input-position elided lifetime, found {}.", multiple_or_none));
+        err.emit();
+
+        hir::Lifetime { hir_id, span, name: hir::LifetimeName::Error }
+    }
+
     fn lower_generic_params(
         &mut self,
         params: &[GenericParam],
@@ -2941,6 +3013,7 @@ impl<'a> LoweringContext<'a> {
                 generics: self.lower_generics(generics, ImplTraitContext::disallowed()),
                 bounds: self.lower_param_bounds(b, ImplTraitContext::disallowed()),
                 impl_trait_fn: None,
+                origin: hir::ExistTyOrigin::ExistentialType,
             }),
             ItemKind::Enum(ref enum_definition, ref generics) => hir::ItemKind::Enum(
                 hir::EnumDef {
@@ -5083,7 +5156,8 @@ impl<'a> LoweringContext<'a> {
     /// with no explicit lifetime.
     fn elided_ref_lifetime(&mut self, span: Span) -> hir::Lifetime {
         match self.anonymous_lifetime_mode {
-            // Intercept when we are in an impl header and introduce an in-band lifetime.
+            // Intercept when we are in an impl header or async fn and introduce an in-band
+            // lifetime.
             // Hence `impl Foo for &u32` becomes `impl<'f> Foo for &'f u32` for some fresh
             // `'f`.
             AnonymousLifetimeMode::CreateParameter => {
@@ -5099,6 +5173,10 @@ impl<'a> LoweringContext<'a> {
             AnonymousLifetimeMode::ReportError => self.new_error_lifetime(None, span),
 
             AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span),
+
+            AnonymousLifetimeMode::Replace(replacement) => {
+                self.new_replacement_lifetime(replacement, span)
+            }
         }
     }
 
@@ -5133,6 +5211,12 @@ impl<'a> LoweringContext<'a> {
     /// sorts of cases are deprecated. This may therefore report a warning or an
     /// error, depending on the mode.
     fn elided_path_lifetimes(&mut self, span: Span, count: usize) -> P<[hir::Lifetime]> {
+        (0..count)
+            .map(|_| self.elided_path_lifetime(span))
+            .collect()
+    }
+
+    fn elided_path_lifetime(&mut self, span: Span) -> hir::Lifetime {
         match self.anonymous_lifetime_mode {
             // N.B., We intentionally ignore the create-parameter mode here
             // and instead "pass through" to resolve-lifetimes, which will then
@@ -5140,21 +5224,16 @@ impl<'a> LoweringContext<'a> {
             // impl elision for deprecated forms like
             //
             //     impl Foo for std::cell::Ref<u32> // note lack of '_
-            AnonymousLifetimeMode::CreateParameter => {}
+            AnonymousLifetimeMode::CreateParameter |
+            // This is the normal case.
+            AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span),
 
-            AnonymousLifetimeMode::ReportError => {
-                return (0..count)
-                    .map(|_| self.new_error_lifetime(None, span))
-                    .collect();
+            AnonymousLifetimeMode::Replace(replacement) => {
+                self.new_replacement_lifetime(replacement, span)
             }
 
-            // This is the normal case.
-            AnonymousLifetimeMode::PassThrough => {}
+            AnonymousLifetimeMode::ReportError => self.new_error_lifetime(None, span),
         }
-
-        (0..count)
-            .map(|_| self.new_implicit_lifetime(span))
-            .collect()
     }
 
     /// Invoked to create the lifetime argument(s) for an elided trait object
@@ -5184,11 +5263,25 @@ impl<'a> LoweringContext<'a> {
 
             // This is the normal case.
             AnonymousLifetimeMode::PassThrough => {}
+
+            // We don't need to do any replacement here as this lifetime
+            // doesn't refer to an elided lifetime elsewhere in the function
+            // signature.
+            AnonymousLifetimeMode::Replace(_) => {}
         }
 
         self.new_implicit_lifetime(span)
     }
 
+    fn new_replacement_lifetime(
+        &mut self,
+        replacement: LtReplacement,
+        span: Span,
+    ) -> hir::Lifetime {
+        let LoweredNodeId { node_id: _, hir_id } = self.next_id();
+        self.replace_elided_lifetime(hir_id, span, replacement)
+    }
+
     fn new_implicit_lifetime(&mut self, span: Span) -> hir::Lifetime {
         let LoweredNodeId { node_id: _, hir_id } = self.next_id();
 
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 8509ddaccf7..58a27d3f78e 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1799,6 +1799,18 @@ pub struct ExistTy {
     pub generics: Generics,
     pub bounds: GenericBounds,
     pub impl_trait_fn: Option<DefId>,
+    pub origin: ExistTyOrigin,
+}
+
+/// Where the existential type came from
+#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
+pub enum ExistTyOrigin {
+    /// `existential type Foo: Trait;`
+    ExistentialType,
+    /// `-> impl Trait`
+    ReturnImplTrait,
+    /// `async fn`
+    AsyncFn,
 }
 
 /// The various kinds of types recognized by the compiler.
diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs
index 8bd20843163..be9460ad86f 100644
--- a/src/librustc/infer/opaque_types/mod.rs
+++ b/src/librustc/infer/opaque_types/mod.rs
@@ -67,6 +67,9 @@ pub struct OpaqueTypeDecl<'tcx> {
     /// the fn body). (Ultimately, writeback is responsible for this
     /// check.)
     pub has_required_region_bounds: bool,
+
+    /// The origin of the existential type
+    pub origin: hir::ExistTyOrigin,
 }
 
 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
@@ -326,14 +329,39 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                         // There are two regions (`lr` and
                         // `subst_arg`) which are not relatable. We can't
                         // find a best choice.
-                        self.tcx
+                        let context_name = match opaque_defn.origin {
+                            hir::ExistTyOrigin::ExistentialType => "existential type",
+                            hir::ExistTyOrigin::ReturnImplTrait => "impl Trait",
+                            hir::ExistTyOrigin::AsyncFn => "async fn",
+                        };
+                        let msg = format!("ambiguous lifetime bound in `{}`", context_name);
+                        let mut err = self.tcx
                             .sess
-                            .struct_span_err(span, "ambiguous lifetime bound in `impl Trait`")
-                            .span_label(
-                                span,
-                                format!("neither `{}` nor `{}` outlives the other", lr, subst_arg),
-                            )
-                            .emit();
+                            .struct_span_err(span, &msg);
+
+                        let lr_name = lr.to_string();
+                        let subst_arg_name = subst_arg.to_string();
+                        let label_owned;
+                        let label = match (&*lr_name, &*subst_arg_name) {
+                            ("'_", "'_") => "the elided lifetimes here do not outlive one another",
+                            _ => {
+                                label_owned = format!(
+                                    "neither `{}` nor `{}` outlives the other",
+                                    lr_name,
+                                    subst_arg_name,
+                                );
+                                &label_owned
+                            }
+                        };
+                        err.span_label(span, label);
+
+                        if let hir::ExistTyOrigin::AsyncFn = opaque_defn.origin {
+                            err.note("multiple unrelated lifetimes are not allowed in \
+                                     `async fn`.");
+                            err.note("if you're using argument-position elided lifetimes, consider \
+                                switching to a single named lifetime.");
+                        }
+                        err.emit();
 
                         least_region = Some(self.tcx.mk_region(ty::ReEmpty));
                         break;
@@ -692,31 +720,41 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
                             parent_def_id == tcx.hir()
                                                 .local_def_id_from_hir_id(opaque_parent_hir_id)
                         };
-                        let in_definition_scope = match tcx.hir().find_by_hir_id(opaque_hir_id) {
+                        let (in_definition_scope, origin) =
+                            match tcx.hir().find_by_hir_id(opaque_hir_id)
+                        {
                             Some(Node::Item(item)) => match item.node {
                                 // impl trait
                                 hir::ItemKind::Existential(hir::ExistTy {
                                     impl_trait_fn: Some(parent),
+                                    origin,
                                     ..
-                                }) => parent == self.parent_def_id,
+                                }) => (parent == self.parent_def_id, origin),
                                 // named existential types
                                 hir::ItemKind::Existential(hir::ExistTy {
                                     impl_trait_fn: None,
+                                    origin,
                                     ..
-                                }) => may_define_existential_type(
-                                    tcx,
-                                    self.parent_def_id,
-                                    opaque_hir_id,
+                                }) => (
+                                    may_define_existential_type(
+                                        tcx,
+                                        self.parent_def_id,
+                                        opaque_hir_id,
+                                    ),
+                                    origin,
                                 ),
-                                _ => def_scope_default(),
+                                _ => (def_scope_default(), hir::ExistTyOrigin::ExistentialType),
                             },
                             Some(Node::ImplItem(item)) => match item.node {
-                                hir::ImplItemKind::Existential(_) => may_define_existential_type(
-                                    tcx,
-                                    self.parent_def_id,
-                                    opaque_hir_id,
+                                hir::ImplItemKind::Existential(_) => (
+                                    may_define_existential_type(
+                                        tcx,
+                                        self.parent_def_id,
+                                        opaque_hir_id,
+                                    ),
+                                    hir::ExistTyOrigin::ExistentialType,
                                 ),
-                                _ => def_scope_default(),
+                                _ => (def_scope_default(), hir::ExistTyOrigin::ExistentialType),
                             },
                             _ => bug!(
                                 "expected (impl) item, found {}",
@@ -724,7 +762,7 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
                             ),
                         };
                         if in_definition_scope {
-                            return self.fold_opaque_ty(ty, def_id, substs);
+                            return self.fold_opaque_ty(ty, def_id, substs, origin);
                         }
 
                         debug!(
@@ -746,6 +784,7 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
         ty: Ty<'tcx>,
         def_id: DefId,
         substs: SubstsRef<'tcx>,
+        origin: hir::ExistTyOrigin,
     ) -> Ty<'tcx> {
         let infcx = self.infcx;
         let tcx = infcx.tcx;
@@ -795,6 +834,7 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
                 substs,
                 concrete_ty: ty_var,
                 has_required_region_bounds: !required_region_bounds.is_empty(),
+                origin,
             },
         );
         debug!("instantiate_opaque_types: ty_var={:?}", ty_var);
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 73e232a6a4f..3306bcae212 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -2891,7 +2891,7 @@ fn insert_late_bound_lifetimes(
     }
 }
 
-fn report_missing_lifetime_specifiers(
+pub fn report_missing_lifetime_specifiers(
     sess: &Session,
     span: Span,
     count: usize,
diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs
index fc04c7672db..280e75476b7 100644
--- a/src/librustc/mir/interpret/error.rs
+++ b/src/librustc/mir/interpret/error.rs
@@ -43,7 +43,7 @@ pub type ConstEvalResult<'tcx> = Result<ty::Const<'tcx>, ErrorHandled>;
 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
 pub struct ConstEvalErr<'tcx> {
     pub span: Span,
-    pub error: crate::mir::interpret::EvalErrorKind<'tcx, u64>,
+    pub error: crate::mir::interpret::InterpError<'tcx, u64>,
     pub stacktrace: Vec<FrameInfo<'tcx>>,
 }
 
@@ -135,10 +135,10 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
         lint_root: Option<hir::HirId>,
     ) -> Result<DiagnosticBuilder<'tcx>, ErrorHandled> {
         match self.error {
-            EvalErrorKind::Layout(LayoutError::Unknown(_)) |
-            EvalErrorKind::TooGeneric => return Err(ErrorHandled::TooGeneric),
-            EvalErrorKind::Layout(LayoutError::SizeOverflow(_)) |
-            EvalErrorKind::TypeckError => return Err(ErrorHandled::Reported),
+            InterpError::Layout(LayoutError::Unknown(_)) |
+            InterpError::TooGeneric => return Err(ErrorHandled::TooGeneric),
+            InterpError::Layout(LayoutError::SizeOverflow(_)) |
+            InterpError::TypeckError => return Err(ErrorHandled::Reported),
             _ => {},
         }
         trace!("reporting const eval failure at {:?}", self.span);
@@ -180,7 +180,7 @@ pub fn struct_error<'a, 'gcx, 'tcx>(
 
 #[derive(Debug, Clone)]
 pub struct EvalError<'tcx> {
-    pub kind: EvalErrorKind<'tcx, u64>,
+    pub kind: InterpError<'tcx, u64>,
     pub backtrace: Option<Box<Backtrace>>,
 }
 
@@ -197,8 +197,8 @@ fn print_backtrace(backtrace: &mut Backtrace) {
     eprintln!("\n\nAn error occurred in miri:\n{:?}", backtrace);
 }
 
-impl<'tcx> From<EvalErrorKind<'tcx, u64>> for EvalError<'tcx> {
-    fn from(kind: EvalErrorKind<'tcx, u64>) -> Self {
+impl<'tcx> From<InterpError<'tcx, u64>> for EvalError<'tcx> {
+    fn from(kind: InterpError<'tcx, u64>) -> Self {
         let backtrace = match env::var("RUST_CTFE_BACKTRACE") {
             // matching RUST_BACKTRACE, we treat "0" the same as "not present".
             Ok(ref val) if val != "0" => {
@@ -221,10 +221,10 @@ impl<'tcx> From<EvalErrorKind<'tcx, u64>> for EvalError<'tcx> {
     }
 }
 
-pub type AssertMessage<'tcx> = EvalErrorKind<'tcx, mir::Operand<'tcx>>;
+pub type AssertMessage<'tcx> = InterpError<'tcx, mir::Operand<'tcx>>;
 
 #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
-pub enum EvalErrorKind<'tcx, O> {
+pub enum InterpError<'tcx, O> {
     /// This variant is used by machines to signal their own errors that do not
     /// match an existing variant.
     MachineError(String),
@@ -312,9 +312,9 @@ pub enum EvalErrorKind<'tcx, O> {
 
 pub type EvalResult<'tcx, T = ()> = Result<T, EvalError<'tcx>>;
 
-impl<'tcx, O> EvalErrorKind<'tcx, O> {
+impl<'tcx, O> InterpError<'tcx, O> {
     pub fn description(&self) -> &str {
-        use self::EvalErrorKind::*;
+        use self::InterpError::*;
         match *self {
             MachineError(ref inner) => inner,
             FunctionAbiMismatch(..) | FunctionArgMismatch(..) | FunctionRetMismatch(..)
@@ -450,15 +450,15 @@ impl<'tcx> fmt::Display for EvalError<'tcx> {
     }
 }
 
-impl<'tcx> fmt::Display for EvalErrorKind<'tcx, u64> {
+impl<'tcx> fmt::Display for InterpError<'tcx, u64> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "{:?}", self)
     }
 }
 
-impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> {
+impl<'tcx, O: fmt::Debug> fmt::Debug for InterpError<'tcx, O> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        use self::EvalErrorKind::*;
+        use self::InterpError::*;
         match *self {
             PointerOutOfBounds { ptr, check, allocation_size } => {
                 write!(f, "Pointer must be in-bounds{} at offset {}, but is outside bounds of \
diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs
index 0dd83168527..2c619a7a250 100644
--- a/src/librustc/mir/interpret/mod.rs
+++ b/src/librustc/mir/interpret/mod.rs
@@ -2,7 +2,7 @@
 
 #[macro_export]
 macro_rules! err {
-    ($($tt:tt)*) => { Err($crate::mir::interpret::EvalErrorKind::$($tt)*.into()) };
+    ($($tt:tt)*) => { Err($crate::mir::interpret::InterpError::$($tt)*.into()) };
 }
 
 mod error;
@@ -11,7 +11,7 @@ mod allocation;
 mod pointer;
 
 pub use self::error::{
-    EvalError, EvalResult, EvalErrorKind, AssertMessage, ConstEvalErr, struct_error,
+    EvalError, EvalResult, InterpError, AssertMessage, ConstEvalErr, struct_error,
     FrameInfo, ConstEvalRawResult, ConstEvalResult, ErrorHandled,
 };
 
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 7b419e306db..a7ab0d6cb04 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -5,7 +5,7 @@
 use crate::hir::def::{CtorKind, Namespace};
 use crate::hir::def_id::DefId;
 use crate::hir::{self, HirId, InlineAsm};
-use crate::mir::interpret::{ConstValue, EvalErrorKind, Scalar};
+use crate::mir::interpret::{ConstValue, InterpError, Scalar};
 use crate::mir::visit::MirVisitable;
 use rustc_apfloat::ieee::{Double, Single};
 use rustc_apfloat::Float;
@@ -3226,8 +3226,8 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
                 target,
                 cleanup,
             } => {
-                let msg = if let EvalErrorKind::BoundsCheck { ref len, ref index } = *msg {
-                    EvalErrorKind::BoundsCheck {
+                let msg = if let InterpError::BoundsCheck { ref len, ref index } = *msg {
+                    InterpError::BoundsCheck {
                         len: len.fold_with(folder),
                         index: index.fold_with(folder),
                     }
@@ -3301,7 +3301,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
                 ref cond, ref msg, ..
             } => {
                 if cond.visit_with(visitor) {
-                    if let EvalErrorKind::BoundsCheck { ref len, ref index } = *msg {
+                    if let InterpError::BoundsCheck { ref len, ref index } = *msg {
                         len.visit_with(visitor) || index.visit_with(visitor)
                     } else {
                         false
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 54e5bfc4397..4d44dc197cb 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -560,7 +560,7 @@ macro_rules! make_mir_visitor {
             fn super_assert_message(&mut self,
                                     msg: & $($mutability)? AssertMessage<'tcx>,
                                     location: Location) {
-                use crate::mir::interpret::EvalErrorKind::*;
+                use crate::mir::interpret::InterpError::*;
                 if let BoundsCheck { len, index } = msg {
                     self.visit_operand(len, location);
                     self.visit_operand(index, location);
diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index 26442faa321..53e8f7ed88b 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -2,7 +2,7 @@ use rustc::middle::lang_items;
 use rustc::ty::{self, Ty, TypeFoldable};
 use rustc::ty::layout::{self, LayoutOf, HasTyCtxt};
 use rustc::mir::{self, Place, PlaceBase, Static, StaticKind};
-use rustc::mir::interpret::EvalErrorKind;
+use rustc::mir::interpret::InterpError;
 use rustc_target::abi::call::{ArgType, FnType, PassMode, IgnoreMode};
 use rustc_target::spec::abi::Abi;
 use rustc_mir::monomorphize;
@@ -365,7 +365,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         // checked operation, just a comparison with the minimum
         // value, so we have to check for the assert message.
         if !bx.check_overflow() {
-            if let mir::interpret::EvalErrorKind::OverflowNeg = *msg {
+            if let mir::interpret::InterpError::OverflowNeg = *msg {
                 const_cond = Some(expected);
             }
         }
@@ -400,7 +400,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
         // Put together the arguments to the panic entry point.
         let (lang_item, args) = match *msg {
-            EvalErrorKind::BoundsCheck { ref len, ref index } => {
+            InterpError::BoundsCheck { ref len, ref index } => {
                 let len = self.codegen_operand(&mut bx, len).immediate();
                 let index = self.codegen_operand(&mut bx, index).immediate();
 
diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs
index 95701204cab..a94350f9cde 100644
--- a/src/librustc_mir/borrow_check/error_reporting.rs
+++ b/src/librustc_mir/borrow_check/error_reporting.rs
@@ -511,14 +511,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                 )
             }
 
-            (BorrowKind::Shallow, _, _, BorrowKind::Unique, _, _)
-            | (BorrowKind::Shallow, _, _, BorrowKind::Mut { .. }, _, _) => {
-                // Shallow borrows are uses from the user's point of view.
-                self.report_use_while_mutably_borrowed(context, (place, span), issued_borrow);
-                return;
-            }
             (BorrowKind::Shared, _, _, BorrowKind::Shared, _, _)
             | (BorrowKind::Shared, _, _, BorrowKind::Shallow, _, _)
+            | (BorrowKind::Shallow, _, _, BorrowKind::Mut { .. }, _, _)
+            | (BorrowKind::Shallow, _, _, BorrowKind::Unique, _, _)
             | (BorrowKind::Shallow, _, _, BorrowKind::Shared, _, _)
             | (BorrowKind::Shallow, _, _, BorrowKind::Shallow, _, _) => unreachable!(),
         };
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 5c159cda141..820a990c633 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -688,7 +688,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
                 cleanup: _,
             } => {
                 self.consume_operand(ContextKind::Assert.new(loc), (cond, span), flow_state);
-                use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
+                use rustc::mir::interpret::InterpError::BoundsCheck;
                 if let BoundsCheck { ref len, ref index } = *msg {
                     self.consume_operand(ContextKind::Assert.new(loc), (len, span), flow_state);
                     self.consume_operand(ContextKind::Assert.new(loc), (index, span), flow_state);
diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/nll/invalidation.rs
index aafbff35776..9f51fb9e969 100644
--- a/src/librustc_mir/borrow_check/nll/invalidation.rs
+++ b/src/librustc_mir/borrow_check/nll/invalidation.rs
@@ -215,7 +215,7 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> {
                 cleanup: _,
             } => {
                 self.consume_operand(ContextKind::Assert.new(location), cond);
-                use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
+                use rustc::mir::interpret::InterpError::BoundsCheck;
                 if let BoundsCheck { ref len, ref index } = *msg {
                     self.consume_operand(ContextKind::Assert.new(location), len);
                     self.consume_operand(ContextKind::Assert.new(location), index);
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 3b559b28f12..5041a7ffee2 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -28,7 +28,7 @@ use rustc::infer::canonical::QueryRegionConstraint;
 use rustc::infer::outlives::env::RegionBoundPairs;
 use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime, NLLRegionVariableOrigin};
 use rustc::infer::type_variable::TypeVariableOrigin;
-use rustc::mir::interpret::{EvalErrorKind::BoundsCheck, ConstValue};
+use rustc::mir::interpret::{InterpError::BoundsCheck, ConstValue};
 use rustc::mir::tcx::PlaceTy;
 use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext, NonMutatingUseContext};
 use rustc::mir::*;
diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs
index 199d03ac445..f7cf0902013 100644
--- a/src/librustc_mir/build/expr/as_place.rs
+++ b/src/librustc_mir/build/expr/as_place.rs
@@ -4,7 +4,7 @@ use crate::build::expr::category::Category;
 use crate::build::ForGuard::{OutsideGuard, RefWithinGuard};
 use crate::build::{BlockAnd, BlockAndExtension, Builder};
 use crate::hair::*;
-use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
+use rustc::mir::interpret::InterpError::BoundsCheck;
 use rustc::mir::*;
 use rustc::ty::{CanonicalUserTypeAnnotation, Variance};
 
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index 84f74484e60..7289dd96edb 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -7,7 +7,7 @@ use crate::build::expr::category::{Category, RvalueFunc};
 use crate::build::{BlockAnd, BlockAndExtension, Builder};
 use crate::hair::*;
 use rustc::middle::region;
-use rustc::mir::interpret::EvalErrorKind;
+use rustc::mir::interpret::InterpError;
 use rustc::mir::*;
 use rustc::ty::{self, CanonicalUserTypeAnnotation, Ty, UpvarSubsts};
 use syntax_pos::Span;
@@ -101,7 +101,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                         block,
                         Operand::Move(is_min),
                         false,
-                        EvalErrorKind::OverflowNeg,
+                        InterpError::OverflowNeg,
                         expr_span,
                     );
                 }
@@ -433,7 +433,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             let val = result_value.clone().field(val_fld, ty);
             let of = result_value.field(of_fld, bool_ty);
 
-            let err = EvalErrorKind::Overflow(op);
+            let err = InterpError::Overflow(op);
 
             block = self.assert(block, Operand::Move(of), false, err, span);
 
@@ -444,9 +444,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 // and 2. there are two possible failure cases, divide-by-zero and overflow.
 
                 let (zero_err, overflow_err) = if op == BinOp::Div {
-                    (EvalErrorKind::DivisionByZero, EvalErrorKind::Overflow(op))
+                    (InterpError::DivisionByZero, InterpError::Overflow(op))
                 } else {
-                    (EvalErrorKind::RemainderByZero, EvalErrorKind::Overflow(op))
+                    (InterpError::RemainderByZero, InterpError::Overflow(op))
                 };
 
                 // Check for / 0
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index 2268568c5f8..33715b749f9 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -23,7 +23,7 @@ use syntax::source_map::{Span, DUMMY_SP};
 use crate::interpret::{self,
     PlaceTy, MPlaceTy, MemPlace, OpTy, ImmTy, Immediate, Scalar, Pointer,
     RawConst, ConstValue,
-    EvalResult, EvalError, EvalErrorKind, GlobalId, InterpretCx, StackPopCleanup,
+    EvalResult, EvalError, InterpError, GlobalId, InterpretCx, StackPopCleanup,
     Allocation, AllocId, MemoryKind,
     snapshot, RefTracking,
 };
@@ -173,7 +173,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
 
 impl<'tcx> Into<EvalError<'tcx>> for ConstEvalError {
     fn into(self) -> EvalError<'tcx> {
-        EvalErrorKind::MachineError(self.to_string()).into()
+        InterpError::MachineError(self.to_string()).into()
     }
 }
 
@@ -351,7 +351,7 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
         Ok(Some(match ecx.load_mir(instance.def) {
             Ok(mir) => mir,
             Err(err) => {
-                if let EvalErrorKind::NoMirFor(ref path) = err.kind {
+                if let InterpError::NoMirFor(ref path) = err.kind {
                     return Err(
                         ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path))
                             .into(),
@@ -679,7 +679,7 @@ pub fn const_eval_raw_provider<'a, 'tcx>(
                 // any other kind of error will be reported to the user as a deny-by-default lint
                 _ => if let Some(p) = cid.promoted {
                     let span = tcx.optimized_mir(def_id).promoted[p].span;
-                    if let EvalErrorKind::ReferencedConstant = err.error {
+                    if let InterpError::ReferencedConstant = err.error {
                         err.report_as_error(
                             tcx.at(span),
                             "evaluation of constant expression failed",
diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs
index fe719bff250..5056d79bec4 100644
--- a/src/librustc_mir/interpret/cast.rs
+++ b/src/librustc_mir/interpret/cast.rs
@@ -4,7 +4,7 @@ use syntax::ast::{FloatTy, IntTy, UintTy};
 
 use rustc_apfloat::ieee::{Single, Double};
 use rustc::mir::interpret::{
-    Scalar, EvalResult, Pointer, PointerArithmetic, EvalErrorKind, truncate
+    Scalar, EvalResult, Pointer, PointerArithmetic, InterpError, truncate
 };
 use rustc::mir::CastKind;
 use rustc_apfloat::Float;
@@ -85,7 +85,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
                             self.param_env,
                             def_id,
                             substs,
-                        ).ok_or_else(|| EvalErrorKind::TooGeneric.into());
+                        ).ok_or_else(|| InterpError::TooGeneric.into());
                         let fn_ptr = self.memory.create_fn_alloc(instance?).with_default_tag();
                         self.write_scalar(Scalar::Ptr(fn_ptr.into()), dest)?;
                     }
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 8b7e28c3de0..535fc58299b 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -16,7 +16,7 @@ use rustc_data_structures::indexed_vec::IndexVec;
 use rustc::mir::interpret::{
     ErrorHandled,
     GlobalId, Scalar, FrameInfo, AllocId,
-    EvalResult, EvalErrorKind,
+    EvalResult, InterpError,
     truncate, sign_extend,
 };
 use rustc_data_structures::fx::FxHashMap;
@@ -167,7 +167,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> LayoutOf
     #[inline]
     fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyLayout {
         self.tcx.layout_of(self.param_env.and(ty))
-            .map_err(|layout| EvalErrorKind::Layout(layout).into())
+            .map_err(|layout| InterpError::Layout(layout).into())
     }
 }
 
@@ -255,7 +255,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc
             self.param_env,
             def_id,
             substs,
-        ).ok_or_else(|| EvalErrorKind::TooGeneric.into())
+        ).ok_or_else(|| InterpError::TooGeneric.into())
     }
 
     pub fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
@@ -647,8 +647,8 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc
         // `Memory::get_static_alloc` which has to use `const_eval_raw` to avoid cycles.
         let val = self.tcx.const_eval_raw(param_env.and(gid)).map_err(|err| {
             match err {
-                ErrorHandled::Reported => EvalErrorKind::ReferencedConstant,
-                ErrorHandled::TooGeneric => EvalErrorKind::TooGeneric,
+                ErrorHandled::Reported => InterpError::ReferencedConstant,
+                ErrorHandled::TooGeneric => InterpError::TooGeneric,
             }
         })?;
         self.raw_const_to_mplace(val)
@@ -670,7 +670,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc
 
                 match self.stack[frame].locals[local].access() {
                     Err(err) => {
-                        if let EvalErrorKind::DeadLocal = err.kind {
+                        if let InterpError::DeadLocal = err.kind {
                             write!(msg, " is dead").unwrap();
                         } else {
                             panic!("Failed to access local: {:?}", err);
diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs
index 99dd654df21..d9721a8cadf 100644
--- a/src/librustc_mir/interpret/intrinsics.rs
+++ b/src/librustc_mir/interpret/intrinsics.rs
@@ -7,7 +7,7 @@ use rustc::ty;
 use rustc::ty::layout::{LayoutOf, Primitive, Size};
 use rustc::mir::BinOp;
 use rustc::mir::interpret::{
-    EvalResult, EvalErrorKind, Scalar,
+    EvalResult, InterpError, Scalar,
 };
 
 use super::{
@@ -87,7 +87,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
                 let bits = self.read_scalar(args[0])?.to_bits(layout_of.size)?;
                 let kind = match layout_of.abi {
                     ty::layout::Abi::Scalar(ref scalar) => scalar.value,
-                    _ => Err(::rustc::mir::interpret::EvalErrorKind::TypeNotPrimitive(ty))?,
+                    _ => Err(::rustc::mir::interpret::InterpError::TypeNotPrimitive(ty))?,
                 };
                 let out_val = if intrinsic_name.ends_with("_nonzero") {
                     if bits == 0 {
@@ -248,7 +248,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
             let file = Symbol::intern(self.read_str(file_place)?);
             let line = self.read_scalar(line.into())?.to_u32()?;
             let col = self.read_scalar(col.into())?.to_u32()?;
-            return Err(EvalErrorKind::Panic { msg, file, line, col }.into());
+            return Err(InterpError::Panic { msg, file, line, col }.into());
         } else if Some(def_id) == self.tcx.lang_items().begin_panic_fn() {
             assert!(args.len() == 2);
             // &'static str, &(&'static str, u32, u32)
@@ -266,7 +266,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
             let file = Symbol::intern(self.read_str(file_place)?);
             let line = self.read_scalar(line.into())?.to_u32()?;
             let col = self.read_scalar(col.into())?.to_u32()?;
-            return Err(EvalErrorKind::Panic { msg, file, line, col }.into());
+            return Err(InterpError::Panic { msg, file, line, col }.into());
         } else {
             return Ok(false);
         }
diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index 6ea200d4e4f..e5d8341dfcf 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -19,7 +19,7 @@ use syntax::ast::Mutability;
 
 use super::{
     Pointer, AllocId, Allocation, GlobalId, AllocationExtra,
-    EvalResult, Scalar, EvalErrorKind, AllocKind, PointerArithmetic,
+    EvalResult, Scalar, InterpError, AllocKind, PointerArithmetic,
     Machine, AllocMap, MayLeak, ErrorHandled, InboundsCheck,
 };
 
@@ -344,8 +344,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
             // no need to report anything, the const_eval call takes care of that for statics
             assert!(tcx.is_static(def_id).is_some());
             match err {
-                ErrorHandled::Reported => EvalErrorKind::ReferencedConstant.into(),
-                ErrorHandled::TooGeneric => EvalErrorKind::TooGeneric.into(),
+                ErrorHandled::Reported => InterpError::ReferencedConstant.into(),
+                ErrorHandled::TooGeneric => InterpError::TooGeneric.into(),
             }
         }).map(|raw_const| {
             let allocation = tcx.alloc_map.lock().unwrap_memory(raw_const.alloc_id);
@@ -458,7 +458,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         trace!("reading fn ptr: {}", ptr.alloc_id);
         match self.tcx.alloc_map.lock().get(ptr.alloc_id) {
             Some(AllocKind::Function(instance)) => Ok(instance),
-            _ => Err(EvalErrorKind::ExecuteMemory.into()),
+            _ => Err(InterpError::ExecuteMemory.into()),
         }
     }
 
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index 38a9371b927..7ea56e36474 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -9,7 +9,7 @@ use rustc::ty::layout::{self, Size, LayoutOf, TyLayout, HasDataLayout, IntegerEx
 use rustc::mir::interpret::{
     GlobalId, AllocId, InboundsCheck,
     ConstValue, Pointer, Scalar,
-    EvalResult, EvalErrorKind,
+    EvalResult, InterpError,
     sign_extend, truncate,
 };
 use super::{
@@ -369,7 +369,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
         let len = mplace.len(self)?;
         let bytes = self.memory.read_bytes(mplace.ptr, Size::from_bytes(len as u64))?;
         let str = ::std::str::from_utf8(bytes)
-            .map_err(|err| EvalErrorKind::ValidationFailure(err.to_string()))?;
+            .map_err(|err| InterpError::ValidationFailure(err.to_string()))?;
         Ok(str)
     }
 
@@ -653,7 +653,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
                     .expect("tagged layout for non adt")
                     .discriminants(self.tcx.tcx)
                     .find(|(_, var)| var.val == real_discr)
-                    .ok_or_else(|| EvalErrorKind::InvalidDiscriminant(raw_discr.erase_tag()))?;
+                    .ok_or_else(|| InterpError::InvalidDiscriminant(raw_discr.erase_tag()))?;
                 (real_discr, index.0)
             },
             layout::DiscriminantKind::Niche {
diff --git a/src/librustc_mir/interpret/snapshot.rs b/src/librustc_mir/interpret/snapshot.rs
index 8bb663f846b..0bafe6d107a 100644
--- a/src/librustc_mir/interpret/snapshot.rs
+++ b/src/librustc_mir/interpret/snapshot.rs
@@ -12,7 +12,7 @@ use rustc::mir;
 use rustc::mir::interpret::{
     AllocId, Pointer, Scalar,
     Relocations, Allocation, UndefMask,
-    EvalResult, EvalErrorKind,
+    EvalResult, InterpError,
 };
 
 use rustc::ty::{self, TyCtxt};
@@ -78,7 +78,7 @@ impl<'a, 'mir, 'tcx> InfiniteLoopDetector<'a, 'mir, 'tcx>
         }
 
         // Second cycle
-        Err(EvalErrorKind::InfiniteLoop.into())
+        Err(InterpError::InfiniteLoop.into())
     }
 }
 
diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs
index 01965f53c15..2080a329bb0 100644
--- a/src/librustc_mir/interpret/terminator.rs
+++ b/src/librustc_mir/interpret/terminator.rs
@@ -5,7 +5,7 @@ use rustc::ty::layout::{self, TyLayout, LayoutOf};
 use syntax::source_map::Span;
 use rustc_target::spec::abi::Abi;
 
-use rustc::mir::interpret::{EvalResult, PointerArithmetic, EvalErrorKind, Scalar};
+use rustc::mir::interpret::{EvalResult, PointerArithmetic, InterpError, Scalar};
 use super::{
     InterpretCx, Machine, Immediate, OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup
 };
@@ -134,7 +134,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
                     self.goto_block(Some(target))?;
                 } else {
                     // Compute error message
-                    use rustc::mir::interpret::EvalErrorKind::*;
+                    use rustc::mir::interpret::InterpError::*;
                     return match *msg {
                         BoundsCheck { ref len, ref index } => {
                             let len = self.read_immediate(self.eval_operand(len, None)?)
@@ -212,7 +212,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
             return Ok(());
         }
         let caller_arg = caller_arg.next()
-            .ok_or_else(|| EvalErrorKind::FunctionArgCountMismatch)?;
+            .ok_or_else(|| InterpError::FunctionArgCountMismatch)?;
         if rust_abi {
             debug_assert!(!caller_arg.layout.is_zst(), "ZSTs must have been already filtered out");
         }
diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs
index 3323ec387bf..d4cf906619d 100644
--- a/src/librustc_mir/interpret/validity.rs
+++ b/src/librustc_mir/interpret/validity.rs
@@ -7,7 +7,7 @@ use rustc::ty::layout::{self, Size, Align, TyLayout, LayoutOf, VariantIdx};
 use rustc::ty;
 use rustc_data_structures::fx::FxHashSet;
 use rustc::mir::interpret::{
-    Scalar, AllocKind, EvalResult, EvalErrorKind,
+    Scalar, AllocKind, EvalResult, InterpError,
 };
 
 use super::{
@@ -258,11 +258,11 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
         match self.walk_value(op) {
             Ok(()) => Ok(()),
             Err(err) => match err.kind {
-                EvalErrorKind::InvalidDiscriminant(val) =>
+                InterpError::InvalidDiscriminant(val) =>
                     validation_failure!(
                         val, self.path, "a valid enum discriminant"
                     ),
-                EvalErrorKind::ReadPointerAsBytes =>
+                InterpError::ReadPointerAsBytes =>
                     validation_failure!(
                         "a pointer", self.path, "plain (non-pointer) bytes"
                     ),
@@ -355,9 +355,9 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
                     Err(err) => {
                         error!("{:?} is not aligned to {:?}", ptr, align);
                         match err.kind {
-                            EvalErrorKind::InvalidNullPointerUsage =>
+                            InterpError::InvalidNullPointerUsage =>
                                 return validation_failure!("NULL reference", self.path),
-                            EvalErrorKind::AlignmentCheckFailed { required, has } =>
+                            InterpError::AlignmentCheckFailed { required, has } =>
                                 return validation_failure!(format!("unaligned reference \
                                     (required {} byte alignment but found {})",
                                     required.bytes(), has.bytes()), self.path),
@@ -562,7 +562,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
                     Err(err) => {
                         // For some errors we might be able to provide extra information
                         match err.kind {
-                            EvalErrorKind::ReadUndefBytes(offset) => {
+                            InterpError::ReadUndefBytes(offset) => {
                                 // Some byte was undefined, determine which
                                 // element that byte belongs to so we can
                                 // provide an index.
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index b3ef7407a7c..0d43602d899 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -7,7 +7,7 @@ use rustc::mir::{Constant, Location, Place, PlaceBase, Mir, Operand, Rvalue, Loc
 use rustc::mir::{NullOp, UnOp, StatementKind, Statement, BasicBlock, LocalKind, Static, StaticKind};
 use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp, ProjectionElem};
 use rustc::mir::visit::{Visitor, PlaceContext, MutatingUseContext, NonMutatingUseContext};
-use rustc::mir::interpret::{EvalErrorKind, Scalar, GlobalId, EvalResult};
+use rustc::mir::interpret::{InterpError, Scalar, GlobalId, EvalResult};
 use rustc::ty::{TyCtxt, self, Instance};
 use syntax::source_map::{Span, DUMMY_SP};
 use rustc::ty::subst::InternalSubsts;
@@ -144,7 +144,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
             Ok(val) => Some(val),
             Err(error) => {
                 let diagnostic = error_to_const_error(&self.ecx, error);
-                use rustc::mir::interpret::EvalErrorKind::*;
+                use rustc::mir::interpret::InterpError::*;
                 match diagnostic.error {
                     // don't report these, they make no sense in a const prop context
                     | MachineError(_)
@@ -457,7 +457,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
                     )
                 } else {
                     if overflow {
-                        let err = EvalErrorKind::Overflow(op).into();
+                        let err = InterpError::Overflow(op).into();
                         let _: Option<()> = self.use_ecx(source_info, |_| Err(err));
                         return None;
                     }
@@ -611,7 +611,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
                         .hir()
                         .as_local_hir_id(self.source.def_id())
                         .expect("some part of a failing const eval must be local");
-                    use rustc::mir::interpret::EvalErrorKind::*;
+                    use rustc::mir::interpret::InterpError::*;
                     let msg = match msg {
                         Overflow(_) |
                         OverflowNeg |
diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index c4e303eb9aa..e63c1899fe5 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -773,7 +773,7 @@ fn create_generator_resume_function<'a, 'tcx>(
 
     let mut cases = create_cases(mir, &transform, |point| Some(point.resume));
 
-    use rustc::mir::interpret::EvalErrorKind::{
+    use rustc::mir::interpret::InterpError::{
         GeneratorResumedAfterPanic,
         GeneratorResumedAfterReturn,
     };
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 9bd5fce31f1..e533066e6b9 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -728,7 +728,10 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
                                    interior mutability, create a static instead");
                     }
                 }
-            } else {
+            } else if let BorrowKind::Mut { .. } | BorrowKind::Shared = kind {
+                // Don't promote BorrowKind::Shallow borrows, as they don't
+                // reach codegen.
+
                 // We might have a candidate for promotion.
                 let candidate = Candidate::Ref(location);
                 // We can only promote interior borrows of promotable temps.
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 5edb8c92a3b..f92fa2e9799 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1979,6 +1979,7 @@ fn explicit_predicates_of<'a, 'tcx>(
                     ref bounds,
                     impl_trait_fn,
                     ref generics,
+                    origin: _,
                 }) => {
                     let substs = InternalSubsts::identity_for_item(tcx, def_id);
                     let opaque_ty = tcx.mk_opaque(def_id, substs);
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index a8c9166591d..4d2c03a4f2f 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -10,6 +10,6 @@ path = "lib.rs"
 
 [dependencies]
 pulldown-cmark = { version = "0.1.2", default-features = false }
-minifier = "0.0.28"
+minifier = "0.0.29"
 tempfile = "3"
 parking_lot = "0.7"
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index f7e8cdeaeca..de434e9d2e3 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -965,7 +965,11 @@ themePicker.onblur = handleThemeButtonsBlur;
                 if for_search_index && line.starts_with("var R") {
                     variables.push(line.clone());
                     // We need to check if the crate name has been put into a variable as well.
-                    let tokens = js::simple_minify(&line).apply(js::clean_tokens);
+                    let tokens: js::Tokens<'_> = js::simple_minify(&line)
+                                                    .into_iter()
+                                                    .filter(js::clean_token)
+                                                    .collect::<Vec<_>>()
+                                                    .into();
                     let mut pos = 0;
                     while pos < tokens.len() {
                         if let Some((var_pos, Some(value_pos))) =
@@ -1288,46 +1292,51 @@ fn write_minify_replacer<W: Write>(
     contents: &str,
     enable_minification: bool,
 ) -> io::Result<()> {
-    use minifier::js::{Keyword, ReservedChar, Token};
+    use minifier::js::{simple_minify, Keyword, ReservedChar, Token, Tokens};
 
     if enable_minification {
         writeln!(dst, "{}",
-                 minifier::js::simple_minify(contents)
-                              .apply(|f| {
-                                  // We keep backlines.
-                                  minifier::js::clean_tokens_except(f, |c| {
-                                      c.get_char() != Some(ReservedChar::Backline)
-                                  })
-                              })
-                              .apply(|f| {
-                                  minifier::js::replace_token_with(f, |t| {
-                                      match *t {
-                                          Token::Keyword(Keyword::Null) => Some(Token::Other("N")),
-                                          Token::String(s) => {
-                                              let s = &s[1..s.len() -1]; // The quotes are included
-                                              if s.is_empty() {
-                                                  Some(Token::Other("E"))
-                                              } else if s == "t" {
-                                                  Some(Token::Other("T"))
-                                              } else if s == "u" {
-                                                  Some(Token::Other("U"))
-                                              } else {
-                                                  None
-                                              }
-                                          }
-                                          _ => None,
-                                      }
-                                  })
-                              })
-                              .apply(|f| {
-                                  // We add a backline after the newly created variables.
-                                  minifier::js::aggregate_strings_into_array_with_separation(
-                                      f,
-                                      "R",
-                                      Token::Char(ReservedChar::Backline),
-                                  )
-                              })
-                              .to_string())
+                 {
+                    let tokens: Tokens<'_> = simple_minify(contents)
+                        .into_iter()
+                        .filter(|f| {
+                            // We keep backlines.
+                            minifier::js::clean_token_except(f, &|c: &Token<'_>| {
+                                c.get_char() != Some(ReservedChar::Backline)
+                            })
+                        })
+                        .map(|f| {
+                            minifier::js::replace_token_with(f, &|t: &Token<'_>| {
+                                match *t {
+                                    Token::Keyword(Keyword::Null) => Some(Token::Other("N")),
+                                    Token::String(s) => {
+                                        let s = &s[1..s.len() -1]; // The quotes are included
+                                        if s.is_empty() {
+                                            Some(Token::Other("E"))
+                                        } else if s == "t" {
+                                            Some(Token::Other("T"))
+                                        } else if s == "u" {
+                                            Some(Token::Other("U"))
+                                        } else {
+                                            None
+                                        }
+                                    }
+                                    _ => None,
+                                }
+                            })
+                        })
+                        .collect::<Vec<_>>()
+                        .into();
+                    tokens.apply(|f| {
+                        // We add a backline after the newly created variables.
+                        minifier::js::aggregate_strings_into_array_with_separation(
+                            f,
+                            "R",
+                            Token::Char(ReservedChar::Backline),
+                        )
+                    })
+                    .to_string()
+                })
     } else {
         writeln!(dst, "{}", contents)
     }
diff --git a/src/libstd/sys/sgx/abi/mod.rs b/src/libstd/sys/sgx/abi/mod.rs
index 85ec8be4aae..1f433e25ee1 100644
--- a/src/libstd/sys/sgx/abi/mod.rs
+++ b/src/libstd/sys/sgx/abi/mod.rs
@@ -69,9 +69,9 @@ extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64
         }
 
         // check entry is being called according to ABI
-        assert_eq!(p3, 0);
-        assert_eq!(p4, 0);
-        assert_eq!(p5, 0);
+        rtassert!(p3 == 0);
+        rtassert!(p4 == 0);
+        rtassert!(p5 == 0);
 
         unsafe {
             // The actual types of these arguments are `p1: *const Arg, p2:
diff --git a/src/libstd/sys/sgx/abi/reloc.rs b/src/libstd/sys/sgx/abi/reloc.rs
index a39841bc36f..6dd24c524fc 100644
--- a/src/libstd/sys/sgx/abi/reloc.rs
+++ b/src/libstd/sys/sgx/abi/reloc.rs
@@ -23,7 +23,7 @@ pub fn relocate_elf_rela() {
     };
     for rela in relas {
         if rela.info != (/*0 << 32 |*/ R_X86_64_RELATIVE as u64) {
-            panic!("Invalid relocation");
+            rtabort!("Invalid relocation");
         }
         unsafe { *mem::rel_ptr_mut::<*const ()>(rela.offset) = mem::rel_ptr(rela.addend) };
     }
diff --git a/src/libstd/sys/sgx/abi/tls.rs b/src/libstd/sys/sgx/abi/tls.rs
index fa82e8ccf05..03e08ad547d 100644
--- a/src/libstd/sys/sgx/abi/tls.rs
+++ b/src/libstd/sys/sgx/abi/tls.rs
@@ -100,20 +100,24 @@ impl Tls {
     }
 
     pub fn create(dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
-        let index = TLS_KEY_IN_USE.set().expect("TLS limit exceeded");
+        let index = if let Some(index) = TLS_KEY_IN_USE.set() {
+            index
+        } else {
+            rtabort!("TLS limit exceeded")
+        };
         TLS_DESTRUCTOR[index].store(dtor.map_or(0, |f| f as usize), Ordering::Relaxed);
         Key::from_index(index)
     }
 
     pub fn set(key: Key, value: *mut u8) {
         let index = key.to_index();
-        assert!(TLS_KEY_IN_USE.get(index));
+        rtassert!(TLS_KEY_IN_USE.get(index));
         unsafe { Self::current() }.data[index].set(value);
     }
 
     pub fn get(key: Key) -> *mut u8 {
         let index = key.to_index();
-        assert!(TLS_KEY_IN_USE.get(index));
+        rtassert!(TLS_KEY_IN_USE.get(index));
         unsafe { Self::current() }.data[index].get()
     }
 
diff --git a/src/libstd/sys/sgx/abi/usercalls/alloc.rs b/src/libstd/sys/sgx/abi/usercalls/alloc.rs
index ec9c30a3e4f..22ae2a8e07d 100644
--- a/src/libstd/sys/sgx/abi/usercalls/alloc.rs
+++ b/src/libstd/sys/sgx/abi/usercalls/alloc.rs
@@ -190,11 +190,15 @@ impl<T: ?Sized> User<T> where T: UserSafe {
         unsafe {
             // Mustn't call alloc with size 0.
             let ptr = if size > 0 {
-                super::alloc(size, T::align_of()).expect("User memory allocation failed") as _
+                rtunwrap!(Ok, super::alloc(size, T::align_of())) as _
             } else {
                 T::align_of() as _ // dangling pointer ok for size 0
             };
-            User(NonNull::new_userref(T::from_raw_sized(ptr, size)))
+            if let Ok(v) = crate::panic::catch_unwind(|| T::from_raw_sized(ptr, size)) {
+                User(NonNull::new_userref(v))
+            } else {
+                rtabort!("Got invalid pointer from alloc() usercall")
+            }
         }
     }
 
diff --git a/src/libstd/sys/sgx/abi/usercalls/mod.rs b/src/libstd/sys/sgx/abi/usercalls/mod.rs
index d84b6154cbe..0abfc26bced 100644
--- a/src/libstd/sys/sgx/abi/usercalls/mod.rs
+++ b/src/libstd/sys/sgx/abi/usercalls/mod.rs
@@ -52,7 +52,7 @@ pub fn close(fd: Fd) {
 
 fn string_from_bytebuffer(buf: &alloc::UserRef<ByteBuffer>, usercall: &str, arg: &str) -> String {
     String::from_utf8(buf.copy_user_buffer())
-        .unwrap_or_else(|_| panic!("Usercall {}: expected {} to be valid UTF-8", usercall, arg))
+        .unwrap_or_else(|_| rtabort!("Usercall {}: expected {} to be valid UTF-8", usercall, arg))
 }
 
 /// Usercall `bind_stream`. See the ABI documentation for more information.
@@ -176,7 +176,7 @@ fn check_os_error(err: Result) -> i32 {
     {
         err
     } else {
-        panic!("Usercall: returned invalid error value {}", err)
+        rtabort!("Usercall: returned invalid error value {}", err)
     }
 }
 
diff --git a/src/libstd/sys/sgx/abi/usercalls/raw.rs b/src/libstd/sys/sgx/abi/usercalls/raw.rs
index ad0b6d7b3d8..e4694a8827a 100644
--- a/src/libstd/sys/sgx/abi/usercalls/raw.rs
+++ b/src/libstd/sys/sgx/abi/usercalls/raw.rs
@@ -131,22 +131,22 @@ impl<T: RegisterArgument> RegisterArgument for Option<NonNull<T>> {
 
 impl ReturnValue for ! {
     fn from_registers(call: &'static str, _regs: (Register, Register)) -> Self {
-        panic!("Usercall {}: did not expect to be re-entered", call);
+        rtabort!("Usercall {}: did not expect to be re-entered", call);
     }
 }
 
 impl ReturnValue for () {
-    fn from_registers(call: &'static str, regs: (Register, Register)) -> Self {
-        assert_eq!(regs.0, 0, "Usercall {}: expected {} return value to be 0", call, "1st");
-        assert_eq!(regs.1, 0, "Usercall {}: expected {} return value to be 0", call, "2nd");
+    fn from_registers(call: &'static str, usercall_retval: (Register, Register)) -> Self {
+        rtassert!(usercall_retval.0 == 0);
+        rtassert!(usercall_retval.1 == 0);
         ()
     }
 }
 
 impl<T: RegisterArgument> ReturnValue for T {
-    fn from_registers(call: &'static str, regs: (Register, Register)) -> Self {
-        assert_eq!(regs.1, 0, "Usercall {}: expected {} return value to be 0", call, "2nd");
-        T::from_register(regs.0)
+    fn from_registers(call: &'static str, usercall_retval: (Register, Register)) -> Self {
+        rtassert!(usercall_retval.1 == 0);
+        T::from_register(usercall_retval.0)
     }
 }
 
@@ -174,8 +174,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
         #[inline(always)]
         pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3, $n4: $t4) -> $r {
             ReturnValue::from_registers(stringify!($f), do_usercall(
-                NonZeroU64::new(Usercalls::$f as Register)
-                    .expect("Usercall number must be non-zero"),
+                rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
                 RegisterArgument::into_register($n1),
                 RegisterArgument::into_register($n2),
                 RegisterArgument::into_register($n3),
@@ -191,8 +190,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
         #[inline(always)]
         pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3) -> $r {
             ReturnValue::from_registers(stringify!($f), do_usercall(
-                NonZeroU64::new(Usercalls::$f as Register)
-                    .expect("Usercall number must be non-zero"),
+                rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
                 RegisterArgument::into_register($n1),
                 RegisterArgument::into_register($n2),
                 RegisterArgument::into_register($n3),
@@ -208,8 +206,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
         #[inline(always)]
         pub unsafe fn $f($n1: $t1, $n2: $t2) -> $r {
             ReturnValue::from_registers(stringify!($f), do_usercall(
-                NonZeroU64::new(Usercalls::$f as Register)
-                    .expect("Usercall number must be non-zero"),
+                rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
                 RegisterArgument::into_register($n1),
                 RegisterArgument::into_register($n2),
                 0,0,
@@ -224,8 +221,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
         #[inline(always)]
         pub unsafe fn $f($n1: $t1) -> $r {
             ReturnValue::from_registers(stringify!($f), do_usercall(
-                NonZeroU64::new(Usercalls::$f as Register)
-                    .expect("Usercall number must be non-zero"),
+                rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
                 RegisterArgument::into_register($n1),
                 0,0,0,
                 return_type_is_abort!($r)
@@ -239,8 +235,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
         #[inline(always)]
         pub unsafe fn $f() -> $r {
             ReturnValue::from_registers(stringify!($f), do_usercall(
-                NonZeroU64::new(Usercalls::$f as Register)
-                    .expect("Usercall number must be non-zero"),
+                rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
                 0,0,0,0,
                 return_type_is_abort!($r)
             ))
diff --git a/src/libstd/sys/sgx/condvar.rs b/src/libstd/sys/sgx/condvar.rs
index f9a76f0baf5..000bb19f269 100644
--- a/src/libstd/sys/sgx/condvar.rs
+++ b/src/libstd/sys/sgx/condvar.rs
@@ -32,9 +32,8 @@ impl Condvar {
         mutex.lock()
     }
 
-    pub unsafe fn wait_timeout(&self, mutex: &Mutex, _dur: Duration) -> bool {
-        mutex.unlock(); // don't hold the lock while panicking
-        panic!("timeout not supported in SGX");
+    pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
+        rtabort!("timeout not supported in SGX");
     }
 
     #[inline]
diff --git a/src/libstd/sys/sgx/mod.rs b/src/libstd/sys/sgx/mod.rs
index dc51a932c61..b0679f65f0d 100644
--- a/src/libstd/sys/sgx/mod.rs
+++ b/src/libstd/sys/sgx/mod.rs
@@ -139,7 +139,7 @@ pub fn hashmap_random_keys() -> (u64, u64) {
                     return ret;
                 }
             }
-            panic!("Failed to obtain random data");
+            rtabort!("Failed to obtain random data");
         }
     }
     (rdrand64(), rdrand64())
diff --git a/src/libstd/sys/sgx/rwlock.rs b/src/libstd/sys/sgx/rwlock.rs
index 4cba36aa64d..09b5ffb1996 100644
--- a/src/libstd/sys/sgx/rwlock.rs
+++ b/src/libstd/sys/sgx/rwlock.rs
@@ -105,7 +105,7 @@ impl RWLock {
                 *wguard.lock_var_mut() = true;
             } else {
                 // No writers were waiting, the lock is released
-                assert!(rguard.queue_empty());
+                rtassert!(rguard.queue_empty());
             }
         }
     }
diff --git a/src/libstd/sys/sgx/thread.rs b/src/libstd/sys/sgx/thread.rs
index a3637723ba1..565a523ebe0 100644
--- a/src/libstd/sys/sgx/thread.rs
+++ b/src/libstd/sys/sgx/thread.rs
@@ -62,17 +62,15 @@ impl Thread {
     }
 
     pub(super) fn entry() {
-        let mut guard = task_queue::lock();
-        let task = guard.pop().expect("Thread started but no tasks pending");
-        drop(guard); // make sure to not hold the task queue lock longer than necessary
+        let mut pending_tasks = task_queue::lock();
+        let task = rtunwrap!(Some, pending_tasks.pop());
+        drop(pending_tasks); // make sure to not hold the task queue lock longer than necessary
         task.run()
     }
 
     pub fn yield_now() {
-        assert_eq!(
-            usercalls::wait(0, usercalls::raw::WAIT_NO).unwrap_err().kind(),
-            io::ErrorKind::WouldBlock
-        );
+        let wait_error = rtunwrap!(Err, usercalls::wait(0, usercalls::raw::WAIT_NO));
+        rtassert!(wait_error.kind() == io::ErrorKind::WouldBlock);
     }
 
     pub fn set_name(_name: &CStr) {
@@ -80,7 +78,7 @@ impl Thread {
     }
 
     pub fn sleep(_dur: Duration) {
-        panic!("can't sleep"); // FIXME
+        rtabort!("can't sleep"); // FIXME
     }
 
     pub fn join(self) {
diff --git a/src/libstd/sys/sgx/waitqueue.rs b/src/libstd/sys/sgx/waitqueue.rs
index f4adb7d1e16..d542f9b4101 100644
--- a/src/libstd/sys/sgx/waitqueue.rs
+++ b/src/libstd/sys/sgx/waitqueue.rs
@@ -121,7 +121,7 @@ impl<'a, T> Drop for WaitGuard<'a, T> {
             NotifiedTcs::Single(tcs) => Some(tcs),
             NotifiedTcs::All { .. } => None
         };
-        usercalls::send(EV_UNPARK, target_tcs).unwrap();
+        rtunwrap!(Ok, usercalls::send(EV_UNPARK, target_tcs));
     }
 }
 
@@ -141,6 +141,7 @@ impl WaitQueue {
     ///
     /// This function does not return until this thread has been awoken.
     pub fn wait<T>(mut guard: SpinMutexGuard<'_, WaitVariable<T>>) {
+        // very unsafe: check requirements of UnsafeList::push
         unsafe {
             let mut entry = UnsafeListEntry::new(SpinMutex::new(WaitEntry {
                 tcs: thread::current(),
@@ -149,10 +150,9 @@ impl WaitQueue {
             let entry = guard.queue.inner.push(&mut entry);
             drop(guard);
             while !entry.lock().wake {
-                assert_eq!(
-                    usercalls::wait(EV_UNPARK, WAIT_INDEFINITE).unwrap() & EV_UNPARK,
-                    EV_UNPARK
-                );
+                // don't panic, this would invalidate `entry` during unwinding
+                let eventset = rtunwrap!(Ok, usercalls::wait(EV_UNPARK, WAIT_INDEFINITE));
+                rtassert!(eventset & EV_UNPARK == EV_UNPARK);
             }
         }
     }
@@ -269,7 +269,7 @@ mod unsafe_list {
                         // ,-------> /---------\ next ---,
                         // |         |head_tail|         |
                         // `--- prev \---------/ <-------`
-                        assert_eq!(self.head_tail.as_ref().prev, first);
+                        rtassert!(self.head_tail.as_ref().prev == first);
                         true
                     } else {
                         false
@@ -285,7 +285,9 @@ mod unsafe_list {
         /// # Safety
         ///
         /// The entry must remain allocated until the entry is removed from the
-        /// list AND the caller who popped is done using the entry.
+        /// list AND the caller who popped is done using the entry. Special
+        /// care must be taken in the caller of `push` to ensure unwinding does
+        /// not destroy the stack frame containing the entry.
         pub unsafe fn push<'a>(&mut self, entry: &'a mut UnsafeListEntry<T>) -> &'a T {
             self.init();
 
@@ -303,6 +305,7 @@ mod unsafe_list {
             entry.as_mut().prev = prev_tail;
             entry.as_mut().next = self.head_tail;
             prev_tail.as_mut().next = entry;
+            // unwrap ok: always `Some` on non-dummy entries
             (*entry.as_ptr()).value.as_ref().unwrap()
         }
 
@@ -333,6 +336,7 @@ mod unsafe_list {
                 second.as_mut().prev = self.head_tail;
                 first.as_mut().next = NonNull::dangling();
                 first.as_mut().prev = NonNull::dangling();
+                // unwrap ok: always `Some` on non-dummy entries
                 Some((*first.as_ptr()).value.as_ref().unwrap())
             }
         }
diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs
index 883ab34f07c..4c64e9f3afb 100644
--- a/src/libstd/sys_common/mod.rs
+++ b/src/libstd/sys_common/mod.rs
@@ -28,6 +28,15 @@ macro_rules! rtassert {
     })
 }
 
+#[allow(unused_macros)] // not used on all platforms
+macro_rules! rtunwrap {
+    ($ok:ident, $e:expr) => (if let $ok(v) = $e {
+        v
+    } else {
+        rtabort!(concat!("unwrap failed: ", stringify!($e)));
+    })
+}
+
 pub mod alloc;
 pub mod at_exit_imp;
 #[cfg(feature = "backtrace")]
diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs
index 0cbf048697a..7ac36a22274 100644
--- a/src/test/mir-opt/match_false_edges.rs
+++ b/src/test/mir-opt/match_false_edges.rs
@@ -70,8 +70,8 @@ fn main() {
 //  }
 //  bb8: { // binding1 and guard
 //      StorageLive(_6);
-//      _6 = &(((promoted[1]: std::option::Option<i32>) as Some).0: i32);
-//      _4 = &shallow (promoted[0]: std::option::Option<i32>);
+//      _6 = &(((promoted[0]: std::option::Option<i32>) as Some).0: i32);
+//      _4 = &shallow _2;
 //      StorageLive(_7);
 //      _7 = const guard() -> [return: bb9, unwind: bb1];
 //  }
diff --git a/src/test/run-pass/async-await.rs b/src/test/run-pass/async-await.rs
index 1843feed927..72af5162992 100644
--- a/src/test/run-pass/async-await.rs
+++ b/src/test/run-pass/async-await.rs
@@ -79,6 +79,11 @@ async fn async_fn(x: u8) -> u8 {
     x
 }
 
+async fn generic_async_fn<T>(x: T) -> T {
+    await!(wake_and_yield_once());
+    x
+}
+
 async fn async_fn_with_borrow(x: &u8) -> u8 {
     await!(wake_and_yield_once());
     *x
@@ -96,14 +101,21 @@ fn async_fn_with_impl_future_named_lifetime<'a>(x: &'a u8) -> impl Future<Output
     }
 }
 
-async fn async_fn_with_named_lifetime_multiple_args<'a>(x: &'a u8, _y: &'a u8) -> u8 {
+/* FIXME(cramertj) support when `existential type T<'a, 'b>:;` works
+async fn async_fn_multiple_args(x: &u8, _y: &u8) -> u8 {
+    await!(wake_and_yield_once());
+    *x
+}
+*/
+
+async fn async_fn_multiple_args_named_lifetime<'a>(x: &'a u8, _y: &'a u8) -> u8 {
     await!(wake_and_yield_once());
     *x
 }
 
 fn async_fn_with_internal_borrow(y: u8) -> impl Future<Output = u8> {
     async move {
-        await!(async_fn_with_borrow(&y))
+        await!(async_fn_with_borrow_named_lifetime(&y))
     }
 }
 
@@ -162,6 +174,7 @@ fn main() {
         async_nonmove_block,
         async_closure,
         async_fn,
+        generic_async_fn,
         async_fn_with_internal_borrow,
         Foo::async_method,
         |x| {
@@ -170,7 +183,6 @@ fn main() {
             }
         },
     }
-
     test_with_borrow! {
         async_block_with_borrow_named_lifetime,
         async_fn_with_borrow,
@@ -178,7 +190,7 @@ fn main() {
         async_fn_with_impl_future_named_lifetime,
         |x| {
             async move {
-                await!(async_fn_with_named_lifetime_multiple_args(x, x))
+                await!(async_fn_multiple_args_named_lifetime(x, x))
             }
         },
     }
diff --git a/src/test/ui/async-fn-multiple-lifetimes.rs b/src/test/ui/async-fn-multiple-lifetimes.rs
index 6156617c4da..fccc4fdb917 100644
--- a/src/test/ui/async-fn-multiple-lifetimes.rs
+++ b/src/test/ui/async-fn-multiple-lifetimes.rs
@@ -5,7 +5,7 @@
 use std::ops::Add;
 
 async fn multiple_named_lifetimes<'a, 'b>(_: &'a u8, _: &'b u8) {}
-//~^ ERROR multiple different lifetimes used in arguments of `async fn`
+//~^ ERROR ambiguous lifetime bound in `async fn`
 
 async fn multiple_hrtb_and_single_named_lifetime_ok<'c>(
     _: impl for<'a> Add<&'a u8>,
@@ -14,7 +14,6 @@ async fn multiple_hrtb_and_single_named_lifetime_ok<'c>(
 ) {}
 
 async fn multiple_elided_lifetimes(_: &u8, _: &u8) {}
-//~^ ERROR multiple elided lifetimes used
-//~^^ ERROR missing lifetime specifier
+//~^ ambiguous lifetime bound in `async fn`
 
 fn main() {}
diff --git a/src/test/ui/async-fn-multiple-lifetimes.stderr b/src/test/ui/async-fn-multiple-lifetimes.stderr
index 071349b23fa..8c3ee2bed83 100644
--- a/src/test/ui/async-fn-multiple-lifetimes.stderr
+++ b/src/test/ui/async-fn-multiple-lifetimes.stderr
@@ -1,32 +1,20 @@
-error[E0709]: multiple different lifetimes used in arguments of `async fn`
-  --> $DIR/async-fn-multiple-lifetimes.rs:7:47
+error: ambiguous lifetime bound in `async fn`
+  --> $DIR/async-fn-multiple-lifetimes.rs:7:65
    |
 LL | async fn multiple_named_lifetimes<'a, 'b>(_: &'a u8, _: &'b u8) {}
-   |                                               ^^         ^^ different lifetime here
-   |                                               |
-   |                                               first lifetime here
+   |                                                                 ^ neither `'a` nor `'b` outlives the other
    |
-   = help: `async fn` can only accept borrowed values with identical lifetimes
+   = note: multiple unrelated lifetimes are not allowed in `async fn`.
+   = note: if you're using argument-position elided lifetimes, consider switching to a single named lifetime.
 
-error[E0707]: multiple elided lifetimes used in arguments of `async fn`
-  --> $DIR/async-fn-multiple-lifetimes.rs:16:39
+error: ambiguous lifetime bound in `async fn`
+  --> $DIR/async-fn-multiple-lifetimes.rs:16:52
    |
 LL | async fn multiple_elided_lifetimes(_: &u8, _: &u8) {}
-   |                                       ^       ^ different lifetime here
-   |                                       |
-   |                                       first lifetime here
+   |                                                    ^ the elided lifetimes here do not outlive one another
    |
-   = help: consider giving these arguments named lifetimes
+   = note: multiple unrelated lifetimes are not allowed in `async fn`.
+   = note: if you're using argument-position elided lifetimes, consider switching to a single named lifetime.
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/async-fn-multiple-lifetimes.rs:16:39
-   |
-LL | async fn multiple_elided_lifetimes(_: &u8, _: &u8) {}
-   |                                       ^ expected lifetime parameter
-   |
-   = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `_` or `_`
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-Some errors occurred: E0106, E0707, E0709.
-For more information about an error, try `rustc --explain E0106`.
diff --git a/src/test/ui/issues/issue-54974.rs b/src/test/ui/issues/issue-54974.rs
new file mode 100644
index 00000000000..b2624ec92a1
--- /dev/null
+++ b/src/test/ui/issues/issue-54974.rs
@@ -0,0 +1,16 @@
+// compile-pass
+// edition:2018
+
+#![feature(async_await, await_macro, futures_api)]
+
+use std::sync::Arc;
+
+trait SomeTrait: Send + Sync + 'static {
+    fn do_something(&self);
+}
+
+async fn my_task(obj: Arc<SomeTrait>) {
+    unimplemented!()
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-55324.rs b/src/test/ui/issues/issue-55324.rs
new file mode 100644
index 00000000000..6160fbabd96
--- /dev/null
+++ b/src/test/ui/issues/issue-55324.rs
@@ -0,0 +1,14 @@
+// compile-pass
+// edition:2018
+
+#![feature(async_await, await_macro, futures_api)]
+
+use std::future::Future;
+
+#[allow(unused)]
+async fn foo<F: Future<Output = i32>>(x: &i32, future: F) -> i32 {
+    let y = await!(future);
+    *x + y
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-58885.rs b/src/test/ui/issues/issue-58885.rs
new file mode 100644
index 00000000000..559899194fb
--- /dev/null
+++ b/src/test/ui/issues/issue-58885.rs
@@ -0,0 +1,21 @@
+// compile-pass
+// edition:2018
+
+#![feature(async_await, await_macro, futures_api)]
+
+struct Xyz {
+    a: u64,
+}
+
+trait Foo {}
+
+impl Xyz {
+    async fn do_sth<'a>(
+        &'a self, foo: &'a dyn Foo
+    ) -> bool
+    {
+        true
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-59001.rs b/src/test/ui/issues/issue-59001.rs
new file mode 100644
index 00000000000..a310653fbce
--- /dev/null
+++ b/src/test/ui/issues/issue-59001.rs
@@ -0,0 +1,17 @@
+// compile-pass
+// edition:2018
+
+#![feature(async_await, await_macro, futures_api)]
+
+use std::future::Future;
+
+#[allow(unused)]
+async fn enter<'a, F, R>(mut callback: F)
+where
+    F: FnMut(&'a mut i32) -> R,
+    R: Future<Output = ()> + 'a,
+{
+    unimplemented!()
+}
+
+fn main() {}