about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/etc/rust-gdb10
-rwxr-xr-xsrc/etc/rust-gdbgui10
-rw-r--r--src/liballoc/vec.rs61
-rw-r--r--src/libpanic_unwind/lib.rs3
-rw-r--r--src/libpanic_unwind/seh.rs2
-rw-r--r--src/librustc_ast/ast.rs4
-rw-r--r--src/librustc_ast_lowering/item.rs13
-rw-r--r--src/librustc_ast_passes/Cargo.toml1
-rw-r--r--src/librustc_ast_passes/ast_validation.rs68
-rw-r--r--src/librustc_ast_pretty/pprust.rs4
-rw-r--r--src/librustc_error_codes/error_codes/E0501.md20
-rw-r--r--src/librustc_error_codes/error_codes/E0506.md60
-rw-r--r--src/librustc_errors/diagnostic_builder.rs14
-rw-r--r--src/librustc_infer/infer/error_reporting/need_type_info.rs113
-rw-r--r--src/librustc_infer/infer/outlives/verify.rs42
-rw-r--r--src/librustc_lint/builtin.rs13
-rw-r--r--src/librustc_middle/ty/fold.rs14
-rw-r--r--src/librustc_middle/ty/mod.rs115
-rw-r--r--src/librustc_middle/ty/outlives.rs44
-rw-r--r--src/librustc_middle/ty/sty.rs42
-rw-r--r--src/librustc_middle/ty/walk.rs219
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs43
-rw-r--r--src/librustc_mir/interpret/eval_context.rs26
-rw-r--r--src/librustc_mir/interpret/operand.rs2
-rw-r--r--src/librustc_mir/interpret/place.rs14
-rw-r--r--src/librustc_mir/interpret/step.rs11
-rw-r--r--src/librustc_mir/interpret/terminator.rs21
-rw-r--r--src/librustc_mir/monomorphize/collector.rs21
-rw-r--r--src/librustc_mir/transform/const_prop.rs6
-rw-r--r--src/librustc_mir/transform/qualify_min_const_fn.rs11
-rw-r--r--src/librustc_passes/layout_test.rs2
-rw-r--r--src/librustc_resolve/def_collector.rs7
-rw-r--r--src/librustc_target/spec/aarch64_pc_windows_msvc.rs5
-rw-r--r--src/librustc_target/spec/aarch64_uwp_windows_msvc.rs5
-rw-r--r--src/librustc_trait_selection/traits/coherence.rs79
-rw-r--r--src/librustc_trait_selection/traits/error_reporting/suggestions.rs3
-rw-r--r--src/librustc_trait_selection/traits/fulfill.rs21
-rw-r--r--src/librustc_trait_selection/traits/object_safety.rs47
-rw-r--r--src/librustc_trait_selection/traits/select.rs125
-rw-r--r--src/librustc_trait_selection/traits/wf.rs23
-rw-r--r--src/librustc_traits/lowering/environment.rs25
-rw-r--r--src/librustc_typeck/astconv.rs6
-rw-r--r--src/librustc_typeck/check/coercion.rs24
-rw-r--r--src/librustc_typeck/check/mod.rs76
-rw-r--r--src/librustc_typeck/outlives/implicit_infer.rs12
-rw-r--r--src/librustdoc/clean/auto_trait.rs41
-rw-r--r--src/librustdoc/clean/mod.rs104
-rw-r--r--src/libstd/io/mod.rs170
m---------src/llvm-project0
-rw-r--r--src/test/ui/coherence/impl-foreign-for-locally-defined-fundamental.rs4
-rw-r--r--src/test/ui/consts/const-eval/issue-70723.rs5
-rw-r--r--src/test/ui/consts/const-eval/issue-70723.stderr9
-rw-r--r--src/test/ui/impl-trait/does-not-live-long-enough.stderr2
-rw-r--r--src/test/ui/layout/debug.rs10
-rw-r--r--src/test/ui/layout/debug.stderr10
-rw-r--r--src/test/ui/parser/issue-32214.stderr7
-rw-r--r--src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs20
-rw-r--r--src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr65
-rw-r--r--src/test/ui/sanitize/inline-always.rs (renamed from src/test/ui/sanitize-inline-always.rs)0
-rw-r--r--src/test/ui/sanitize/inline-always.stderr (renamed from src/test/ui/sanitize-inline-always.stderr)4
-rw-r--r--src/test/ui/suggestions/suggest-move-types.stderr108
61 files changed, 1230 insertions, 816 deletions
diff --git a/src/etc/rust-gdb b/src/etc/rust-gdb
index 23ba93da8e5..b950cea79ed 100755
--- a/src/etc/rust-gdb
+++ b/src/etc/rust-gdb
@@ -2,8 +2,16 @@
 # Exit if anything fails
 set -e
 
+# Prefer rustc in the same directory as this script
+DIR="$(dirname "$0")"
+if [ -x "$DIR/rustc" ]; then
+  RUSTC="$DIR/rustc"
+else
+  RUSTC="rustc"
+fi
+
 # Find out where the pretty printer Python module is
-RUSTC_SYSROOT=`rustc --print=sysroot`
+RUSTC_SYSROOT="$("$RUSTC" --print=sysroot)"
 GDB_PYTHON_MODULE_DIRECTORY="$RUSTC_SYSROOT/lib/rustlib/etc"
 
 # Run GDB with the additional arguments that load the pretty printers
diff --git a/src/etc/rust-gdbgui b/src/etc/rust-gdbgui
index 08d598cde1c..9744913b686 100755
--- a/src/etc/rust-gdbgui
+++ b/src/etc/rust-gdbgui
@@ -31,8 +31,16 @@ icon to start your program running.
     exit 0
 fi
 
+# Prefer rustc in the same directory as this script
+DIR="$(dirname "$0")"
+if [ -x "$DIR/rustc" ]; then
+  RUSTC="$DIR/rustc"
+else
+  RUSTC="rustc"
+fi
+
 # Find out where the pretty printer Python module is
-RUSTC_SYSROOT=`rustc --print=sysroot`
+RUSTC_SYSROOT="$("$RUSTC" --print=sysroot)"
 GDB_PYTHON_MODULE_DIRECTORY="$RUSTC_SYSROOT/lib/rustlib/etc"
 
 # Set the environment variable `RUST_GDB` to overwrite the call to a
diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs
index a48e48d7da3..7ef281ff208 100644
--- a/src/liballoc/vec.rs
+++ b/src/liballoc/vec.rs
@@ -964,8 +964,16 @@ impl<T> Vec<T> {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn swap_remove(&mut self, index: usize) -> T {
+        #[cold]
+        #[inline(never)]
+        fn assert_failed(index: usize, len: usize) -> ! {
+            panic!("swap_remove index (is {}) should be < len (is {})", index, len);
+        }
+
         let len = self.len();
-        assert!(index < len);
+        if !(index < len) {
+            assert_failed(index, len);
+        }
         unsafe {
             // We replace self[index] with the last element. Note that if the
             // bounds check above succeeds there must be a last element (which
@@ -995,8 +1003,16 @@ impl<T> Vec<T> {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn insert(&mut self, index: usize, element: T) {
+        #[cold]
+        #[inline(never)]
+        fn assert_failed(index: usize, len: usize) -> ! {
+            panic!("insertion index (is {}) should be <= len (is {})", index, len);
+        }
+
         let len = self.len();
-        assert!(index <= len);
+        if !(index <= len) {
+            assert_failed(index, len);
+        }
 
         // space for the new element
         if len == self.buf.capacity() {
@@ -1035,8 +1051,16 @@ impl<T> Vec<T> {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn remove(&mut self, index: usize) -> T {
+        #[cold]
+        #[inline(never)]
+        fn assert_failed(index: usize, len: usize) -> ! {
+            panic!("removal index (is {}) should be < len (is {})", index, len);
+        }
+
         let len = self.len();
-        assert!(index < len);
+        if !(index < len) {
+            assert_failed(index, len);
+        }
         unsafe {
             // infallible
             let ret;
@@ -1294,8 +1318,25 @@ impl<T> Vec<T> {
             Excluded(&n) => n,
             Unbounded => len,
         };
-        assert!(start <= end);
-        assert!(end <= len);
+
+        #[cold]
+        #[inline(never)]
+        fn start_assert_failed(start: usize, end: usize) -> ! {
+            panic!("start drain index (is {}) should be <= end drain index (is {})", start, end);
+        }
+
+        #[cold]
+        #[inline(never)]
+        fn end_assert_failed(end: usize, len: usize) -> ! {
+            panic!("end drain index (is {}) should be <= len (is {})", end, len);
+        }
+
+        if !(start <= end) {
+            start_assert_failed(start, end);
+        }
+        if !(end <= len) {
+            end_assert_failed(end, len);
+        }
 
         unsafe {
             // set self.vec length's to start, to be safe in case Drain is leaked
@@ -1385,7 +1426,15 @@ impl<T> Vec<T> {
     #[must_use = "use `.truncate()` if you don't need the other half"]
     #[stable(feature = "split_off", since = "1.4.0")]
     pub fn split_off(&mut self, at: usize) -> Self {
-        assert!(at <= self.len(), "`at` out of bounds");
+        #[cold]
+        #[inline(never)]
+        fn assert_failed(at: usize, len: usize) -> ! {
+            panic!("`at` split index (is {}) should be <= len (is {})", at, len);
+        }
+
+        if !(at <= self.len()) {
+            assert_failed(at, self.len());
+        }
 
         let other_len = self.len - at;
         let mut other = Vec::with_capacity(other_len);
diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs
index 0a2a0e9e045..f791fe82a27 100644
--- a/src/libpanic_unwind/lib.rs
+++ b/src/libpanic_unwind/lib.rs
@@ -47,9 +47,6 @@ cfg_if::cfg_if! {
     } else if #[cfg(target_os = "hermit")] {
         #[path = "hermit.rs"]
         mod real_imp;
-    } else if #[cfg(all(target_env = "msvc", target_arch = "aarch64"))] {
-        #[path = "dummy.rs"]
-        mod real_imp;
     } else if #[cfg(target_env = "msvc")] {
         #[path = "seh.rs"]
         mod real_imp;
diff --git a/src/libpanic_unwind/seh.rs b/src/libpanic_unwind/seh.rs
index 10b765a5b41..9eff37f1766 100644
--- a/src/libpanic_unwind/seh.rs
+++ b/src/libpanic_unwind/seh.rs
@@ -117,7 +117,7 @@ mod imp {
     }
 }
 
-#[cfg(any(target_arch = "x86_64", target_arch = "arm"))]
+#[cfg(not(target_arch = "x86"))]
 #[macro_use]
 mod imp {
     pub type ptr_t = u32;
diff --git a/src/librustc_ast/ast.rs b/src/librustc_ast/ast.rs
index 6586280d214..f91cbe51d85 100644
--- a/src/librustc_ast/ast.rs
+++ b/src/librustc_ast/ast.rs
@@ -300,8 +300,8 @@ pub enum GenericBound {
 impl GenericBound {
     pub fn span(&self) -> Span {
         match self {
-            &GenericBound::Trait(ref t, ..) => t.span,
-            &GenericBound::Outlives(ref l) => l.ident.span,
+            GenericBound::Trait(ref t, ..) => t.span,
+            GenericBound::Outlives(ref l) => l.ident.span,
         }
     }
 }
diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs
index 6005b607026..5fe007d6de2 100644
--- a/src/librustc_ast_lowering/item.rs
+++ b/src/librustc_ast_lowering/item.rs
@@ -165,19 +165,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
             }
             ItemKind::MacroDef(..) => SmallVec::new(),
             ItemKind::Fn(..) | ItemKind::Impl { of_trait: None, .. } => smallvec![i.id],
-            ItemKind::Static(ref ty, ..) => {
+            ItemKind::Static(ref ty, ..) | ItemKind::Const(_, ref ty, ..) => {
                 let mut ids = smallvec![i.id];
                 if self.sess.features_untracked().impl_trait_in_bindings {
-                    let mut visitor = ImplTraitTypeIdVisitor { ids: &mut ids };
-                    visitor.visit_ty(ty);
-                }
-                ids
-            }
-            ItemKind::Const(_, ref ty, ..) => {
-                let mut ids = smallvec![i.id];
-                if self.sess.features_untracked().impl_trait_in_bindings {
-                    let mut visitor = ImplTraitTypeIdVisitor { ids: &mut ids };
-                    visitor.visit_ty(ty);
+                    ImplTraitTypeIdVisitor { ids: &mut ids }.visit_ty(ty);
                 }
                 ids
             }
diff --git a/src/librustc_ast_passes/Cargo.toml b/src/librustc_ast_passes/Cargo.toml
index 5d096e4965d..e4d1d79abb2 100644
--- a/src/librustc_ast_passes/Cargo.toml
+++ b/src/librustc_ast_passes/Cargo.toml
@@ -9,6 +9,7 @@ name = "rustc_ast_passes"
 path = "lib.rs"
 
 [dependencies]
+itertools = "0.8"
 log = "0.4"
 rustc_ast_pretty = { path = "../librustc_ast_pretty" }
 rustc_attr = { path = "../librustc_attr" }
diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs
index de7ae10723f..9563325fe32 100644
--- a/src/librustc_ast_passes/ast_validation.rs
+++ b/src/librustc_ast_passes/ast_validation.rs
@@ -6,6 +6,7 @@
 // This pass is supposed to perform only simple checks not requiring name resolution
 // or type checking or some other kind of complex analysis.
 
+use itertools::{Either, Itertools};
 use rustc_ast::ast::*;
 use rustc_ast::attr;
 use rustc_ast::expand::is_proc_macro_attr;
@@ -14,7 +15,7 @@ use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
 use rustc_ast::walk_list;
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{error_code, struct_span_err, Applicability};
+use rustc_errors::{error_code, pluralize, struct_span_err, Applicability};
 use rustc_parse::validate_attr;
 use rustc_session::lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY;
 use rustc_session::lint::LintBuffer;
@@ -640,6 +641,33 @@ impl<'a> AstValidator<'a> {
         }
     }
 
+    fn correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String {
+        // Lifetimes always come first.
+        let lt_sugg = data.args.iter().filter_map(|arg| match arg {
+            AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => {
+                Some(pprust::to_string(|s| s.print_generic_arg(lt)))
+            }
+            _ => None,
+        });
+        let args_sugg = data.args.iter().filter_map(|a| match a {
+            AngleBracketedArg::Arg(GenericArg::Lifetime(_)) | AngleBracketedArg::Constraint(_) => {
+                None
+            }
+            AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))),
+        });
+        // Constraints always come last.
+        let constraint_sugg = data.args.iter().filter_map(|a| match a {
+            AngleBracketedArg::Arg(_) => None,
+            AngleBracketedArg::Constraint(c) => {
+                Some(pprust::to_string(|s| s.print_assoc_constraint(c)))
+            }
+        });
+        format!(
+            "<{}>",
+            lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ")
+        )
+    }
+
     /// Enforce generic args coming before constraints in `<...>` of a path segment.
     fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
         // Early exit in case it's partitioned as it should be.
@@ -647,24 +675,36 @@ impl<'a> AstValidator<'a> {
             return;
         }
         // Find all generic argument coming after the first constraint...
-        let mut misplaced_args = Vec::new();
-        let mut first = None;
-        for arg in &data.args {
-            match (arg, first) {
-                (AngleBracketedArg::Arg(a), Some(_)) => misplaced_args.push(a.span()),
-                (AngleBracketedArg::Constraint(c), None) => first = Some(c.span),
-                (AngleBracketedArg::Arg(_), None) | (AngleBracketedArg::Constraint(_), Some(_)) => {
-                }
-            }
-        }
+        let (constraint_spans, arg_spans): (Vec<Span>, Vec<Span>) =
+            data.args.iter().partition_map(|arg| match arg {
+                AngleBracketedArg::Constraint(c) => Either::Left(c.span),
+                AngleBracketedArg::Arg(a) => Either::Right(a.span()),
+            });
+        let args_len = arg_spans.len();
+        let constraint_len = constraint_spans.len();
         // ...and then error:
         self.err_handler()
             .struct_span_err(
-                misplaced_args.clone(),
+                arg_spans.clone(),
                 "generic arguments must come before the first constraint",
             )
-            .span_label(first.unwrap(), "the first constraint is provided here")
-            .span_labels(misplaced_args, "generic argument")
+            .span_label(constraint_spans[0], &format!("constraint{}", pluralize!(constraint_len)))
+            .span_label(
+                *arg_spans.iter().last().unwrap(),
+                &format!("generic argument{}", pluralize!(args_len)),
+            )
+            .span_labels(constraint_spans, "")
+            .span_labels(arg_spans, "")
+            .span_suggestion_verbose(
+                data.span,
+                &format!(
+                    "move the constraint{} after the generic argument{}",
+                    pluralize!(constraint_len),
+                    pluralize!(args_len)
+                ),
+                self.correct_generic_order_suggestion(&data),
+                Applicability::MachineApplicable,
+            )
             .emit();
     }
 }
diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs
index 6541ac156b4..f68868633f1 100644
--- a/src/librustc_ast_pretty/pprust.rs
+++ b/src/librustc_ast_pretty/pprust.rs
@@ -869,7 +869,7 @@ impl<'a> State<'a> {
         }
     }
 
-    fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) {
+    pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) {
         self.print_ident(constraint.ident);
         self.s.space();
         match &constraint.kind {
@@ -883,7 +883,7 @@ impl<'a> State<'a> {
         }
     }
 
-    crate fn print_generic_arg(&mut self, generic_arg: &GenericArg) {
+    pub fn print_generic_arg(&mut self, generic_arg: &GenericArg) {
         match generic_arg {
             GenericArg::Lifetime(lt) => self.print_lifetime(*lt),
             GenericArg::Type(ty) => self.print_type(ty),
diff --git a/src/librustc_error_codes/error_codes/E0501.md b/src/librustc_error_codes/error_codes/E0501.md
index f5aa17a8094..ffdbc443905 100644
--- a/src/librustc_error_codes/error_codes/E0501.md
+++ b/src/librustc_error_codes/error_codes/E0501.md
@@ -1,12 +1,4 @@
-This error indicates that a mutable variable is being used while it is still
-captured by a closure. Because the closure has borrowed the variable, it is not
-available for use until the closure goes out of scope.
-
-Note that a capture will either move or borrow a variable, but in this
-situation, the closure is borrowing the variable. Take a look at the chapter
-on [Capturing][capturing] in Rust By Example for more information.
-
-[capturing]: https://doc.rust-lang.org/stable/rust-by-example/fn/closures/capture.html
+A mutable variable is used but it is already captured by a closure.
 
 Erroneous code example:
 
@@ -29,6 +21,16 @@ fn foo(a: &mut i32) {
 }
 ```
 
+This error indicates that a mutable variable is used while it is still captured
+by a closure. Because the closure has borrowed the variable, it is not available
+until the closure goes out of scope.
+
+Note that a capture will either move or borrow a variable, but in this
+situation, the closure is borrowing the variable. Take a look at the chapter
+on [Capturing][capturing] in Rust By Example for more information.
+
+[capturing]: https://doc.rust-lang.org/stable/rust-by-example/fn/closures/capture.html
+
 To fix this error, you can finish using the closure before using the captured
 variable:
 
diff --git a/src/librustc_error_codes/error_codes/E0506.md b/src/librustc_error_codes/error_codes/E0506.md
index 9b8e3164872..c312a0460e3 100644
--- a/src/librustc_error_codes/error_codes/E0506.md
+++ b/src/librustc_error_codes/error_codes/E0506.md
@@ -1,4 +1,4 @@
-This error occurs when an attempt is made to assign to a borrowed value.
+An attempt was made to assign to a borrowed value.
 
 Erroneous code example:
 
@@ -7,14 +7,12 @@ struct FancyNum {
     num: u8,
 }
 
-fn main() {
-    let mut fancy_num = FancyNum { num: 5 };
-    let fancy_ref = &fancy_num;
-    fancy_num = FancyNum { num: 6 };
-    // error: cannot assign to `fancy_num` because it is borrowed
+let mut fancy_num = FancyNum { num: 5 };
+let fancy_ref = &fancy_num;
+fancy_num = FancyNum { num: 6 };
+// error: cannot assign to `fancy_num` because it is borrowed
 
-    println!("Num: {}, Ref: {}", fancy_num.num, fancy_ref.num);
-}
+println!("Num: {}, Ref: {}", fancy_num.num, fancy_ref.num);
 ```
 
 Because `fancy_ref` still holds a reference to `fancy_num`, `fancy_num` can't
@@ -27,13 +25,11 @@ struct FancyNum {
     num: u8,
 }
 
-fn main() {
-    let mut fancy_num = FancyNum { num: 5 };
-    let moved_num = fancy_num;
-    fancy_num = FancyNum { num: 6 };
+let mut fancy_num = FancyNum { num: 5 };
+let moved_num = fancy_num;
+fancy_num = FancyNum { num: 6 };
 
-    println!("Num: {}, Moved num: {}", fancy_num.num, moved_num.num);
-}
+println!("Num: {}, Moved num: {}", fancy_num.num, moved_num.num);
 ```
 
 If the value has to be borrowed, try limiting the lifetime of the borrow using
@@ -44,18 +40,16 @@ struct FancyNum {
     num: u8,
 }
 
-fn main() {
-    let mut fancy_num = FancyNum { num: 5 };
-
-    {
-        let fancy_ref = &fancy_num;
-        println!("Ref: {}", fancy_ref.num);
-    }
+let mut fancy_num = FancyNum { num: 5 };
 
-    // Works because `fancy_ref` is no longer in scope
-    fancy_num = FancyNum { num: 6 };
-    println!("Num: {}", fancy_num.num);
+{
+    let fancy_ref = &fancy_num;
+    println!("Ref: {}", fancy_ref.num);
 }
+
+// Works because `fancy_ref` is no longer in scope
+fancy_num = FancyNum { num: 6 };
+println!("Num: {}", fancy_num.num);
 ```
 
 Or by moving the reference into a function:
@@ -65,17 +59,15 @@ struct FancyNum {
     num: u8,
 }
 
-fn main() {
-    let mut fancy_num = FancyNum { num: 5 };
-
-    print_fancy_ref(&fancy_num);
-
-    // Works because function borrow has ended
-    fancy_num = FancyNum { num: 6 };
-    println!("Num: {}", fancy_num.num);
-}
-
 fn print_fancy_ref(fancy_ref: &FancyNum){
     println!("Ref: {}", fancy_ref.num);
 }
+
+let mut fancy_num = FancyNum { num: 5 };
+
+print_fancy_ref(&fancy_num);
+
+// Works because function borrow has ended
+fancy_num = FancyNum { num: 6 };
+println!("Num: {}", fancy_num.num);
 ```
diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs
index fffae0bfd24..2dbd9f4e52f 100644
--- a/src/librustc_errors/diagnostic_builder.rs
+++ b/src/librustc_errors/diagnostic_builder.rs
@@ -315,6 +315,20 @@ impl<'a> DiagnosticBuilder<'a> {
         self
     }
 
+    pub fn span_suggestion_verbose(
+        &mut self,
+        sp: Span,
+        msg: &str,
+        suggestion: String,
+        applicability: Applicability,
+    ) -> &mut Self {
+        if !self.0.allow_suggestions {
+            return self;
+        }
+        self.0.diagnostic.span_suggestion_verbose(sp, msg, suggestion, applicability);
+        self
+    }
+
     pub fn span_suggestion_hidden(
         &mut self,
         sp: Span,
diff --git a/src/librustc_infer/infer/error_reporting/need_type_info.rs b/src/librustc_infer/infer/error_reporting/need_type_info.rs
index 7824855fe05..bb6e5700cca 100644
--- a/src/librustc_infer/infer/error_reporting/need_type_info.rs
+++ b/src/librustc_infer/infer/error_reporting/need_type_info.rs
@@ -7,52 +7,59 @@ use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, Pat};
 use rustc_middle::hir::map::Map;
 use rustc_middle::ty::print::Print;
-use rustc_middle::ty::{self, DefIdTree, Infer, Ty, TyVar};
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
+use rustc_middle::ty::{self, DefIdTree, Ty};
 use rustc_span::source_map::DesugaringKind;
 use rustc_span::symbol::kw;
 use rustc_span::Span;
 use std::borrow::Cow;
 
-struct FindLocalByTypeVisitor<'a, 'tcx> {
+struct FindHirNodeVisitor<'a, 'tcx> {
     infcx: &'a InferCtxt<'a, 'tcx>,
-    target_ty: Ty<'tcx>,
-    hir_map: Map<'tcx>,
+    target: GenericArg<'tcx>,
+    found_node_ty: Option<Ty<'tcx>>,
     found_local_pattern: Option<&'tcx Pat<'tcx>>,
     found_arg_pattern: Option<&'tcx Pat<'tcx>>,
-    found_ty: Option<Ty<'tcx>>,
-    found_closure: Option<&'tcx ExprKind<'tcx>>,
+    found_closure: Option<&'tcx Expr<'tcx>>,
     found_method_call: Option<&'tcx Expr<'tcx>>,
 }
 
-impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> {
-    fn new(infcx: &'a InferCtxt<'a, 'tcx>, target_ty: Ty<'tcx>, hir_map: Map<'tcx>) -> Self {
+impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> {
+    fn new(infcx: &'a InferCtxt<'a, 'tcx>, target: GenericArg<'tcx>) -> Self {
         Self {
             infcx,
-            target_ty,
-            hir_map,
+            target,
+            found_node_ty: None,
             found_local_pattern: None,
             found_arg_pattern: None,
-            found_ty: None,
             found_closure: None,
             found_method_call: None,
         }
     }
 
-    fn node_matches_type(&mut self, hir_id: HirId) -> Option<Ty<'tcx>> {
+    fn node_ty_contains_target(&mut self, hir_id: HirId) -> Option<Ty<'tcx>> {
         let ty_opt =
             self.infcx.in_progress_tables.and_then(|tables| tables.borrow().node_type_opt(hir_id));
         match ty_opt {
             Some(ty) => {
                 let ty = self.infcx.resolve_vars_if_possible(&ty);
-                if ty.walk().any(|inner_ty| {
-                    inner_ty == self.target_ty
-                        || match (&inner_ty.kind, &self.target_ty.kind) {
-                            (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => self
-                                .infcx
-                                .inner
-                                .borrow_mut()
-                                .type_variables
-                                .sub_unified(a_vid, b_vid),
+                if ty.walk().any(|inner| {
+                    inner == self.target
+                        || match (inner.unpack(), self.target.unpack()) {
+                            (GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => {
+                                match (&inner_ty.kind, &target_ty.kind) {
+                                    (
+                                        &ty::Infer(ty::TyVar(a_vid)),
+                                        &ty::Infer(ty::TyVar(b_vid)),
+                                    ) => self
+                                        .infcx
+                                        .inner
+                                        .borrow_mut()
+                                        .type_variables
+                                        .sub_unified(a_vid, b_vid),
+                                    _ => false,
+                                }
+                            }
                             _ => false,
                         }
                 }) {
@@ -66,36 +73,39 @@ impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for FindLocalByTypeVisitor<'a, 'tcx> {
+impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> {
     type Map = Map<'tcx>;
 
     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::OnlyBodies(self.hir_map)
+        NestedVisitorMap::OnlyBodies(self.infcx.tcx.hir())
     }
 
     fn visit_local(&mut self, local: &'tcx Local<'tcx>) {
-        if let (None, Some(ty)) = (self.found_local_pattern, self.node_matches_type(local.hir_id)) {
+        if let (None, Some(ty)) =
+            (self.found_local_pattern, self.node_ty_contains_target(local.hir_id))
+        {
             self.found_local_pattern = Some(&*local.pat);
-            self.found_ty = Some(ty);
+            self.found_node_ty = Some(ty);
         }
         intravisit::walk_local(self, local);
     }
 
     fn visit_body(&mut self, body: &'tcx Body<'tcx>) {
         for param in body.params {
-            if let (None, Some(ty)) = (self.found_arg_pattern, self.node_matches_type(param.hir_id))
+            if let (None, Some(ty)) =
+                (self.found_arg_pattern, self.node_ty_contains_target(param.hir_id))
             {
                 self.found_arg_pattern = Some(&*param.pat);
-                self.found_ty = Some(ty);
+                self.found_node_ty = Some(ty);
             }
         }
         intravisit::walk_body(self, body);
     }
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
-        if self.node_matches_type(expr.hir_id).is_some() {
+        if self.node_ty_contains_target(expr.hir_id).is_some() {
             match expr.kind {
-                ExprKind::Closure(..) => self.found_closure = Some(&expr.kind),
+                ExprKind::Closure(..) => self.found_closure = Some(&expr),
                 ExprKind::MethodCall(..) => self.found_method_call = Some(&expr),
                 _ => {}
             }
@@ -213,6 +223,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         (s, None, ty.prefix_string(), None, None)
     }
 
+    // FIXME(eddyb) generalize all of this to handle `ty::Const` inference variables as well.
     pub fn need_type_info_err(
         &self,
         body_id: Option<hir::BodyId>,
@@ -223,7 +234,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         let ty = self.resolve_vars_if_possible(&ty);
         let (name, name_sp, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None);
 
-        let mut local_visitor = FindLocalByTypeVisitor::new(&self, ty, self.tcx.hir());
+        let mut local_visitor = FindHirNodeVisitor::new(&self, ty.into());
         let ty_to_string = |ty: Ty<'tcx>| -> String {
             let mut s = String::new();
             let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
@@ -276,7 +287,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 (!ty.is_impl_trait() || self.tcx.features().impl_trait_in_bindings)
         };
 
-        let ty_msg = match local_visitor.found_ty {
+        let ty_msg = match local_visitor.found_node_ty {
             Some(ty::TyS { kind: ty::Closure(_, substs), .. }) => {
                 let fn_sig = substs.as_closure().sig();
                 let args = closure_args(&fn_sig);
@@ -310,28 +321,32 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             error_code,
         );
 
-        let suffix = match local_visitor.found_ty {
+        let suffix = match local_visitor.found_node_ty {
             Some(ty::TyS { kind: ty::Closure(_, substs), .. }) => {
                 let fn_sig = substs.as_closure().sig();
                 let ret = fn_sig.output().skip_binder().to_string();
 
-                if let Some(ExprKind::Closure(_, decl, body_id, ..)) = local_visitor.found_closure {
-                    if let Some(body) = self.tcx.hir().krate().bodies.get(body_id) {
-                        closure_return_type_suggestion(
-                            span,
-                            &mut err,
-                            &decl.output,
-                            &body,
-                            &descr,
-                            &name,
-                            &ret,
-                            parent_name,
-                            parent_descr,
-                        );
-                        // We don't want to give the other suggestions when the problem is the
-                        // closure return type.
-                        return err;
-                    }
+                let closure_decl_and_body_id =
+                    local_visitor.found_closure.and_then(|closure| match &closure.kind {
+                        ExprKind::Closure(_, decl, body_id, ..) => Some((decl, *body_id)),
+                        _ => None,
+                    });
+
+                if let Some((decl, body_id)) = closure_decl_and_body_id {
+                    closure_return_type_suggestion(
+                        span,
+                        &mut err,
+                        &decl.output,
+                        self.tcx.hir().body(body_id),
+                        &descr,
+                        &name,
+                        &ret,
+                        parent_name,
+                        parent_descr,
+                    );
+                    // We don't want to give the other suggestions when the problem is the
+                    // closure return type.
+                    return err;
                 }
 
                 // This shouldn't be reachable, but just in case we leave a reasonable fallback.
diff --git a/src/librustc_infer/infer/outlives/verify.rs b/src/librustc_infer/infer/outlives/verify.rs
index 1cd6830b6a2..ed967f7ab3a 100644
--- a/src/librustc_infer/infer/outlives/verify.rs
+++ b/src/librustc_infer/infer/outlives/verify.rs
@@ -3,11 +3,9 @@ use crate::infer::{GenericKind, VerifyBound};
 use crate::traits;
 use rustc_data_structures::captures::Captures;
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::subst::{InternalSubsts, Subst};
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 
-use smallvec::smallvec;
-
 /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a`
 /// obligation into a series of `'a: 'b` constraints and "verifys", as
 /// described on the module comment. The final constraints are emitted
@@ -44,7 +42,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
         match ty.kind {
             ty::Param(p) => self.param_bound(p),
             ty::Projection(data) => self.projection_bound(data),
-            _ => self.recursive_type_bound(ty),
+            _ => self.recursive_bound(ty.into()),
         }
     }
 
@@ -144,25 +142,33 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
 
         // see the extensive comment in projection_must_outlive
         let ty = self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs);
-        let recursive_bound = self.recursive_type_bound(ty);
+        let recursive_bound = self.recursive_bound(ty.into());
 
         VerifyBound::AnyBound(env_bounds.chain(trait_bounds).collect()).or(recursive_bound)
     }
 
-    fn recursive_type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> {
-        let mut bounds = ty.walk_shallow().map(|subty| self.type_bound(subty)).collect::<Vec<_>>();
-
-        let mut regions = smallvec![];
-        ty.push_regions(&mut regions);
-        regions.retain(|r| !r.is_late_bound()); // ignore late-bound regions
-        bounds.push(VerifyBound::AllBounds(
-            regions.into_iter().map(|r| VerifyBound::OutlivedBy(r)).collect(),
-        ));
-
-        // remove bounds that must hold, since they are not interesting
-        bounds.retain(|b| !b.must_hold());
+    fn recursive_bound(&self, parent: GenericArg<'tcx>) -> VerifyBound<'tcx> {
+        let mut bounds = parent
+            .walk_shallow()
+            .filter_map(|child| match child.unpack() {
+                GenericArgKind::Type(ty) => Some(self.type_bound(ty)),
+                GenericArgKind::Lifetime(lt) => {
+                    // Ignore late-bound regions.
+                    if !lt.is_late_bound() { Some(VerifyBound::OutlivedBy(lt)) } else { None }
+                }
+                GenericArgKind::Const(_) => Some(self.recursive_bound(child)),
+            })
+            .filter(|bound| {
+                // Remove bounds that must hold, since they are not interesting.
+                !bound.must_hold()
+            });
 
-        if bounds.len() == 1 { bounds.pop().unwrap() } else { VerifyBound::AllBounds(bounds) }
+        match (bounds.next(), bounds.next()) {
+            (Some(first), None) => first,
+            (first, second) => {
+                VerifyBound::AllBounds(first.into_iter().chain(second).chain(bounds).collect())
+            }
+        }
     }
 
     /// Searches the environment for where-clauses like `G: 'a` where
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index cff86e8f218..84cf2258ac2 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -36,6 +36,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::{GenericParamKind, PatKind};
 use rustc_hir::{HirIdSet, Node};
 use rustc_middle::lint::LintDiagnosticBuilder;
+use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::lint::FutureIncompatibleInfo;
 use rustc_span::edition::Edition;
@@ -104,11 +105,13 @@ declare_lint_pass!(BoxPointers => [BOX_POINTERS]);
 
 impl BoxPointers {
     fn check_heap_type(&self, cx: &LateContext<'_, '_>, span: Span, ty: Ty<'_>) {
-        for leaf_ty in ty.walk() {
-            if leaf_ty.is_box() {
-                cx.struct_span_lint(BOX_POINTERS, span, |lint| {
-                    lint.build(&format!("type uses owned (Box type) pointers: {}", ty)).emit()
-                });
+        for leaf in ty.walk() {
+            if let GenericArgKind::Type(leaf_ty) = leaf.unpack() {
+                if leaf_ty.is_box() {
+                    cx.struct_span_lint(BOX_POINTERS, span, |lint| {
+                        lint.build(&format!("type uses owned (Box type) pointers: {}", ty)).emit()
+                    });
+                }
             }
         }
     }
diff --git a/src/librustc_middle/ty/fold.rs b/src/librustc_middle/ty/fold.rs
index a3d611a1325..7b23460eb6e 100644
--- a/src/librustc_middle/ty/fold.rs
+++ b/src/librustc_middle/ty/fold.rs
@@ -263,20 +263,6 @@ where
 // Region folder
 
 impl<'tcx> TyCtxt<'tcx> {
-    /// Collects the free and escaping regions in `value` into `region_set`. Returns
-    /// whether any late-bound regions were skipped
-    pub fn collect_regions<T>(self, value: &T, region_set: &mut FxHashSet<ty::Region<'tcx>>) -> bool
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        let mut have_bound_regions = false;
-        self.fold_regions(value, &mut have_bound_regions, |r, d| {
-            region_set.insert(self.mk_region(r.shifted_out_to_binder(d)));
-            r
-        });
-        have_bound_regions
-    }
-
     /// Folds the escaping and free regions in `value` using `f`, and
     /// sets `skipped_regions` to true if any late-bound region was found
     /// and skipped.
diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs
index 0ebd55a6c02..1870856150f 100644
--- a/src/librustc_middle/ty/mod.rs
+++ b/src/librustc_middle/ty/mod.rs
@@ -19,7 +19,6 @@ use crate::traits::{self, Reveal};
 use crate::ty;
 use crate::ty::subst::{InternalSubsts, Subst, SubstsRef};
 use crate::ty::util::{Discr, IntTypeExt};
-use crate::ty::walk::TypeWalker;
 use rustc_ast::ast::{self, Ident, Name};
 use rustc_ast::node_id::{NodeId, NodeMap, NodeSet};
 use rustc_attr as attr;
@@ -1366,10 +1365,6 @@ impl<'tcx> TraitPredicate<'tcx> {
         self.trait_ref.def_id
     }
 
-    pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'a {
-        self.trait_ref.input_types()
-    }
-
     pub fn self_ty(&self) -> Ty<'tcx> {
         self.trait_ref.self_ty()
     }
@@ -1519,77 +1514,7 @@ impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> {
     }
 }
 
-// A custom iterator used by `Predicate::walk_tys`.
-enum WalkTysIter<'tcx, I, J, K>
-where
-    I: Iterator<Item = Ty<'tcx>>,
-    J: Iterator<Item = Ty<'tcx>>,
-    K: Iterator<Item = Ty<'tcx>>,
-{
-    None,
-    One(Ty<'tcx>),
-    Two(Ty<'tcx>, Ty<'tcx>),
-    Types(I),
-    InputTypes(J),
-    ProjectionTypes(K),
-}
-
-impl<'tcx, I, J, K> Iterator for WalkTysIter<'tcx, I, J, K>
-where
-    I: Iterator<Item = Ty<'tcx>>,
-    J: Iterator<Item = Ty<'tcx>>,
-    K: Iterator<Item = Ty<'tcx>>,
-{
-    type Item = Ty<'tcx>;
-
-    fn next(&mut self) -> Option<Ty<'tcx>> {
-        match *self {
-            WalkTysIter::None => None,
-            WalkTysIter::One(item) => {
-                *self = WalkTysIter::None;
-                Some(item)
-            }
-            WalkTysIter::Two(item1, item2) => {
-                *self = WalkTysIter::One(item2);
-                Some(item1)
-            }
-            WalkTysIter::Types(ref mut iter) => iter.next(),
-            WalkTysIter::InputTypes(ref mut iter) => iter.next(),
-            WalkTysIter::ProjectionTypes(ref mut iter) => iter.next(),
-        }
-    }
-}
-
 impl<'tcx> Predicate<'tcx> {
-    /// Iterates over the types in this predicate. Note that in all
-    /// cases this is skipping over a binder, so late-bound regions
-    /// with depth 0 are bound by the predicate.
-    pub fn walk_tys(&'a self) -> impl Iterator<Item = Ty<'tcx>> + 'a {
-        match *self {
-            ty::Predicate::Trait(ref data, _) => {
-                WalkTysIter::InputTypes(data.skip_binder().input_types())
-            }
-            ty::Predicate::Subtype(binder) => {
-                let SubtypePredicate { a, b, a_is_expected: _ } = binder.skip_binder();
-                WalkTysIter::Two(a, b)
-            }
-            ty::Predicate::TypeOutlives(binder) => WalkTysIter::One(binder.skip_binder().0),
-            ty::Predicate::RegionOutlives(..) => WalkTysIter::None,
-            ty::Predicate::Projection(ref data) => {
-                let inner = data.skip_binder();
-                WalkTysIter::ProjectionTypes(
-                    inner.projection_ty.substs.types().chain(Some(inner.ty)),
-                )
-            }
-            ty::Predicate::WellFormed(data) => WalkTysIter::One(data),
-            ty::Predicate::ObjectSafe(_trait_def_id) => WalkTysIter::None,
-            ty::Predicate::ClosureKind(_closure_def_id, closure_substs, _kind) => {
-                WalkTysIter::Types(closure_substs.types())
-            }
-            ty::Predicate::ConstEvaluatable(_, substs) => WalkTysIter::Types(substs.types()),
-        }
-    }
-
     pub fn to_opt_poly_trait_ref(&self) -> Option<PolyTraitRef<'tcx>> {
         match *self {
             Predicate::Trait(ref t, _) => Some(t.to_poly_trait_ref()),
@@ -2686,46 +2611,6 @@ impl<'tcx> ClosureKind {
     }
 }
 
-impl<'tcx> TyS<'tcx> {
-    /// Iterator that walks `self` and any types reachable from
-    /// `self`, in depth-first order. Note that just walks the types
-    /// that appear in `self`, it does not descend into the fields of
-    /// structs or variants. For example:
-    ///
-    /// ```notrust
-    /// isize => { isize }
-    /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
-    /// [isize] => { [isize], isize }
-    /// ```
-    pub fn walk(&'tcx self) -> TypeWalker<'tcx> {
-        TypeWalker::new(self)
-    }
-
-    /// Iterator that walks the immediate children of `self`. Hence
-    /// `Foo<Bar<i32>, u32>` yields the sequence `[Bar<i32>, u32]`
-    /// (but not `i32`, like `walk`).
-    pub fn walk_shallow(&'tcx self) -> smallvec::IntoIter<walk::TypeWalkerArray<'tcx>> {
-        walk::walk_shallow(self)
-    }
-
-    /// Walks `ty` and any types appearing within `ty`, invoking the
-    /// callback `f` on each type. If the callback returns `false`, then the
-    /// children of the current type are ignored.
-    ///
-    /// Note: prefer `ty.walk()` where possible.
-    pub fn maybe_walk<F>(&'tcx self, mut f: F)
-    where
-        F: FnMut(Ty<'tcx>) -> bool,
-    {
-        let mut walker = self.walk();
-        while let Some(ty) = walker.next() {
-            if !f(ty) {
-                walker.skip_current_subtree();
-            }
-        }
-    }
-}
-
 impl BorrowKind {
     pub fn from_mutbl(m: hir::Mutability) -> BorrowKind {
         match m {
diff --git a/src/librustc_middle/ty/outlives.rs b/src/librustc_middle/ty/outlives.rs
index 9dd96f2f2b5..950539fbb0a 100644
--- a/src/librustc_middle/ty/outlives.rs
+++ b/src/librustc_middle/ty/outlives.rs
@@ -2,6 +2,7 @@
 // refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that
 // RFC for reference.
 
+use crate::ty::subst::{GenericArg, GenericArgKind};
 use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
 use smallvec::SmallVec;
 
@@ -107,8 +108,9 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo
                     // fallback case: hard code
                     // OutlivesProjectionComponents.  Continue walking
                     // through and constrain Pi.
-                    let subcomponents = capture_components(tcx, ty);
-                    out.push(Component::EscapingProjection(subcomponents));
+                    let mut subcomponents = smallvec![];
+                    compute_components_recursive(tcx, ty.into(), &mut subcomponents);
+                    out.push(Component::EscapingProjection(subcomponents.into_iter().collect()));
                 }
             }
 
@@ -153,26 +155,30 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo
                 // "bound regions list".  In our representation, no such
                 // list is maintained explicitly, because bound regions
                 // themselves can be readily identified.
-
-                push_region_constraints(ty, out);
-                for subty in ty.walk_shallow() {
-                    compute_components(tcx, subty, out);
-                }
+                compute_components_recursive(tcx, ty.into(), out);
             }
         }
 }
 
-fn capture_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Vec<Component<'tcx>> {
-    let mut temp = smallvec![];
-    push_region_constraints(ty, &mut temp);
-    for subty in ty.walk_shallow() {
-        compute_components(tcx, subty, &mut temp);
+fn compute_components_recursive(
+    tcx: TyCtxt<'tcx>,
+    parent: GenericArg<'tcx>,
+    out: &mut SmallVec<[Component<'tcx>; 4]>,
+) {
+    for child in parent.walk_shallow() {
+        match child.unpack() {
+            GenericArgKind::Type(ty) => {
+                compute_components(tcx, ty, out);
+            }
+            GenericArgKind::Lifetime(lt) => {
+                // Ignore late-bound regions.
+                if !lt.is_late_bound() {
+                    out.push(Component::Region(lt));
+                }
+            }
+            GenericArgKind::Const(_) => {
+                compute_components_recursive(tcx, child, out);
+            }
+        }
     }
-    temp.into_iter().collect()
-}
-
-fn push_region_constraints<'tcx>(ty: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) {
-    let mut regions = smallvec![];
-    ty.push_regions(&mut regions);
-    out.extend(regions.iter().filter(|&r| !r.is_late_bound()).map(|r| Component::Region(r)));
 }
diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs
index ef815aaab75..f0932788687 100644
--- a/src/librustc_middle/ty/sty.rs
+++ b/src/librustc_middle/ty/sty.rs
@@ -25,7 +25,6 @@ use rustc_macros::HashStable;
 use rustc_span::symbol::{kw, Symbol};
 use rustc_target::abi::{Size, VariantIdx};
 use rustc_target::spec::abi;
-use smallvec::SmallVec;
 use std::borrow::Cow;
 use std::cmp::Ordering;
 use std::marker::PhantomData;
@@ -755,14 +754,6 @@ impl<'tcx> TraitRef<'tcx> {
         self.substs.type_at(0)
     }
 
-    pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'a {
-        // Select only the "input types" from a trait-reference. For
-        // now this is all the types that appear in the
-        // trait-reference, but it should eventually exclude
-        // associated types.
-        self.substs.types()
-    }
-
     pub fn from_method(
         tcx: TyCtxt<'tcx>,
         trait_id: DefId,
@@ -806,14 +797,6 @@ pub struct ExistentialTraitRef<'tcx> {
 }
 
 impl<'tcx> ExistentialTraitRef<'tcx> {
-    pub fn input_types<'b>(&'b self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'b {
-        // Select only the "input types" from a trait-reference. For
-        // now this is all the types that appear in the
-        // trait-reference, but it should eventually exclude
-        // associated types.
-        self.substs.types()
-    }
-
     pub fn erase_self_ty(
         tcx: TyCtxt<'tcx>,
         trait_ref: ty::TraitRef<'tcx>,
@@ -2152,31 +2135,6 @@ impl<'tcx> TyS<'tcx> {
         }
     }
 
-    /// Pushes onto `out` the regions directly referenced from this type (but not
-    /// types reachable from this type via `walk_tys`). This ignores late-bound
-    /// regions binders.
-    pub fn push_regions(&self, out: &mut SmallVec<[ty::Region<'tcx>; 4]>) {
-        match self.kind {
-            Ref(region, _, _) => {
-                out.push(region);
-            }
-            Dynamic(ref obj, region) => {
-                out.push(region);
-                if let Some(principal) = obj.principal() {
-                    out.extend(principal.skip_binder().substs.regions());
-                }
-            }
-            Adt(_, substs) | Opaque(_, substs) => out.extend(substs.regions()),
-            Closure(_, ref substs) | Generator(_, ref substs, _) => out.extend(substs.regions()),
-            Projection(ref data) | UnnormalizedProjection(ref data) => {
-                out.extend(data.substs.regions())
-            }
-            FnDef(..) | FnPtr(_) | GeneratorWitness(..) | Bool | Char | Int(_) | Uint(_)
-            | Float(_) | Str | Array(..) | Slice(_) | RawPtr(_) | Never | Tuple(..)
-            | Foreign(..) | Param(_) | Bound(..) | Placeholder(..) | Infer(_) | Error => {}
-        }
-    }
-
     /// When we create a closure, we record its kind (i.e., what trait
     /// it implements) into its `ClosureSubsts` using a type
     /// parameter. This is kind of a phantom type, except that the
diff --git a/src/librustc_middle/ty/walk.rs b/src/librustc_middle/ty/walk.rs
index da08fbcf144..c7a317f39ad 100644
--- a/src/librustc_middle/ty/walk.rs
+++ b/src/librustc_middle/ty/walk.rs
@@ -1,13 +1,13 @@
 //! An iterator over the type substructure.
 //! WARNING: this does not keep track of the region depth.
 
-use crate::ty::{self, Ty};
+use crate::ty;
+use crate::ty::subst::{GenericArg, GenericArgKind};
 use smallvec::{self, SmallVec};
 
 // The TypeWalker's stack is hot enough that it's worth going to some effort to
 // avoid heap allocations.
-pub type TypeWalkerArray<'tcx> = [Ty<'tcx>; 8];
-pub type TypeWalkerStack<'tcx> = SmallVec<TypeWalkerArray<'tcx>>;
+type TypeWalkerStack<'tcx> = SmallVec<[GenericArg<'tcx>; 8]>;
 
 pub struct TypeWalker<'tcx> {
     stack: TypeWalkerStack<'tcx>,
@@ -15,11 +15,11 @@ pub struct TypeWalker<'tcx> {
 }
 
 impl<'tcx> TypeWalker<'tcx> {
-    pub fn new(ty: Ty<'tcx>) -> TypeWalker<'tcx> {
-        TypeWalker { stack: smallvec![ty], last_subtree: 1 }
+    pub fn new(root: GenericArg<'tcx>) -> TypeWalker<'tcx> {
+        TypeWalker { stack: smallvec![root], last_subtree: 1 }
     }
 
-    /// Skips the subtree of types corresponding to the last type
+    /// Skips the subtree corresponding to the last type
     /// returned by `next()`.
     ///
     /// Example: Imagine you are walking `Foo<Bar<int>, usize>`.
@@ -37,102 +37,145 @@ impl<'tcx> TypeWalker<'tcx> {
 }
 
 impl<'tcx> Iterator for TypeWalker<'tcx> {
-    type Item = Ty<'tcx>;
+    type Item = GenericArg<'tcx>;
 
-    fn next(&mut self) -> Option<Ty<'tcx>> {
+    fn next(&mut self) -> Option<GenericArg<'tcx>> {
         debug!("next(): stack={:?}", self.stack);
-        match self.stack.pop() {
-            None => None,
-            Some(ty) => {
-                self.last_subtree = self.stack.len();
-                push_subtypes(&mut self.stack, ty);
-                debug!("next: stack={:?}", self.stack);
-                Some(ty)
-            }
-        }
+        let next = self.stack.pop()?;
+        self.last_subtree = self.stack.len();
+        push_inner(&mut self.stack, next);
+        debug!("next: stack={:?}", self.stack);
+        Some(next)
     }
 }
 
-pub fn walk_shallow(ty: Ty<'_>) -> smallvec::IntoIter<TypeWalkerArray<'_>> {
-    let mut stack = SmallVec::new();
-    push_subtypes(&mut stack, ty);
-    stack.into_iter()
+impl GenericArg<'tcx> {
+    /// Iterator that walks `self` and any types reachable from
+    /// `self`, in depth-first order. Note that just walks the types
+    /// that appear in `self`, it does not descend into the fields of
+    /// structs or variants. For example:
+    ///
+    /// ```notrust
+    /// isize => { isize }
+    /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
+    /// [isize] => { [isize], isize }
+    /// ```
+    pub fn walk(self) -> TypeWalker<'tcx> {
+        TypeWalker::new(self)
+    }
+
+    /// Iterator that walks the immediate children of `self`. Hence
+    /// `Foo<Bar<i32>, u32>` yields the sequence `[Bar<i32>, u32]`
+    /// (but not `i32`, like `walk`).
+    pub fn walk_shallow(self) -> impl Iterator<Item = GenericArg<'tcx>> {
+        let mut stack = SmallVec::new();
+        push_inner(&mut stack, self);
+        stack.into_iter()
+    }
 }
 
-// We push types on the stack in reverse order so as to
+impl<'tcx> super::TyS<'tcx> {
+    /// Iterator that walks `self` and any types reachable from
+    /// `self`, in depth-first order. Note that just walks the types
+    /// that appear in `self`, it does not descend into the fields of
+    /// structs or variants. For example:
+    ///
+    /// ```notrust
+    /// isize => { isize }
+    /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
+    /// [isize] => { [isize], isize }
+    /// ```
+    pub fn walk(&'tcx self) -> TypeWalker<'tcx> {
+        TypeWalker::new(self.into())
+    }
+}
+
+// We push `GenericArg`s on the stack in reverse order so as to
 // maintain a pre-order traversal. As of the time of this
 // writing, the fact that the traversal is pre-order is not
 // known to be significant to any code, but it seems like the
 // natural order one would expect (basically, the order of the
 // types as they are written).
-fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
-    match parent_ty.kind {
-        ty::Bool
-        | ty::Char
-        | ty::Int(_)
-        | ty::Uint(_)
-        | ty::Float(_)
-        | ty::Str
-        | ty::Infer(_)
-        | ty::Param(_)
-        | ty::Never
-        | ty::Error
-        | ty::Placeholder(..)
-        | ty::Bound(..)
-        | ty::Foreign(..) => {}
-        ty::Array(ty, len) => {
-            if let ty::ConstKind::Unevaluated(_, substs, promoted) = len.val {
-                assert!(promoted.is_none());
-                stack.extend(substs.types().rev());
+fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) {
+    match parent.unpack() {
+        GenericArgKind::Type(parent_ty) => match parent_ty.kind {
+            ty::Bool
+            | ty::Char
+            | ty::Int(_)
+            | ty::Uint(_)
+            | ty::Float(_)
+            | ty::Str
+            | ty::Infer(_)
+            | ty::Param(_)
+            | ty::Never
+            | ty::Error
+            | ty::Placeholder(..)
+            | ty::Bound(..)
+            | ty::Foreign(..) => {}
+
+            ty::Array(ty, len) => {
+                stack.push(len.into());
+                stack.push(ty.into());
             }
-            stack.push(len.ty);
-            stack.push(ty);
-        }
-        ty::Slice(ty) => {
-            stack.push(ty);
-        }
-        ty::RawPtr(ref mt) => {
-            stack.push(mt.ty);
-        }
-        ty::Ref(_, ty, _) => {
-            stack.push(ty);
-        }
-        ty::Projection(ref data) | ty::UnnormalizedProjection(ref data) => {
-            stack.extend(data.substs.types().rev());
-        }
-        ty::Dynamic(ref obj, ..) => {
-            stack.extend(obj.iter().rev().flat_map(|predicate| {
-                let (substs, opt_ty) = match *predicate.skip_binder() {
-                    ty::ExistentialPredicate::Trait(tr) => (tr.substs, None),
-                    ty::ExistentialPredicate::Projection(p) => (p.substs, Some(p.ty)),
-                    ty::ExistentialPredicate::AutoTrait(_) =>
-                    // Empty iterator
-                    {
-                        (ty::InternalSubsts::empty(), None)
-                    }
-                };
+            ty::Slice(ty) => {
+                stack.push(ty.into());
+            }
+            ty::RawPtr(mt) => {
+                stack.push(mt.ty.into());
+            }
+            ty::Ref(lt, ty, _) => {
+                stack.push(ty.into());
+                stack.push(lt.into());
+            }
+            ty::Projection(data) | ty::UnnormalizedProjection(data) => {
+                stack.extend(data.substs.iter().copied().rev());
+            }
+            ty::Dynamic(obj, lt) => {
+                stack.push(lt.into());
+                stack.extend(obj.iter().rev().flat_map(|predicate| {
+                    let (substs, opt_ty) = match *predicate.skip_binder() {
+                        ty::ExistentialPredicate::Trait(tr) => (tr.substs, None),
+                        ty::ExistentialPredicate::Projection(p) => (p.substs, Some(p.ty)),
+                        ty::ExistentialPredicate::AutoTrait(_) =>
+                        // Empty iterator
+                        {
+                            (ty::InternalSubsts::empty(), None)
+                        }
+                    };
 
-                substs.types().rev().chain(opt_ty)
-            }));
-        }
-        ty::Adt(_, substs) | ty::Opaque(_, substs) => {
-            stack.extend(substs.types().rev());
-        }
-        ty::Closure(_, ref substs) | ty::Generator(_, ref substs, _) => {
-            stack.extend(substs.types().rev());
-        }
-        ty::GeneratorWitness(ts) => {
-            stack.extend(ts.skip_binder().iter().cloned().rev());
-        }
-        ty::Tuple(..) => {
-            stack.extend(parent_ty.tuple_fields().rev());
-        }
-        ty::FnDef(_, substs) => {
-            stack.extend(substs.types().rev());
-        }
-        ty::FnPtr(sig) => {
-            stack.push(sig.skip_binder().output());
-            stack.extend(sig.skip_binder().inputs().iter().cloned().rev());
+                    substs.iter().copied().rev().chain(opt_ty.map(|ty| ty.into()))
+                }));
+            }
+            ty::Adt(_, substs)
+            | ty::Opaque(_, substs)
+            | ty::Closure(_, substs)
+            | ty::Generator(_, substs, _)
+            | ty::Tuple(substs)
+            | ty::FnDef(_, substs) => {
+                stack.extend(substs.iter().copied().rev());
+            }
+            ty::GeneratorWitness(ts) => {
+                stack.extend(ts.skip_binder().iter().cloned().rev().map(|ty| ty.into()));
+            }
+            ty::FnPtr(sig) => {
+                stack.push(sig.skip_binder().output().into());
+                stack.extend(sig.skip_binder().inputs().iter().cloned().rev().map(|ty| ty.into()));
+            }
+        },
+        GenericArgKind::Lifetime(_) => {}
+        GenericArgKind::Const(parent_ct) => {
+            stack.push(parent_ct.ty.into());
+            match parent_ct.val {
+                ty::ConstKind::Infer(_)
+                | ty::ConstKind::Param(_)
+                | ty::ConstKind::Placeholder(_)
+                | ty::ConstKind::Bound(..)
+                | ty::ConstKind::Value(_) => {}
+
+                ty::ConstKind::Unevaluated(_, substs, _) => {
+                    stack.extend(substs.iter().copied().rev());
+                }
+            }
         }
     }
 }
diff --git a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs
index 7340e88f19b..7645182ad1f 100644
--- a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs
@@ -208,45 +208,34 @@ impl BorrowExplanation {
                     );
                 };
 
-                self.add_lifetime_bound_suggestion_to_diagnostic(
-                    tcx,
-                    err,
-                    &category,
-                    span,
-                    region_name,
-                );
+                self.add_lifetime_bound_suggestion_to_diagnostic(err, &category, span, region_name);
             }
             _ => {}
         }
     }
-    pub(in crate::borrow_check) fn add_lifetime_bound_suggestion_to_diagnostic<'tcx>(
+    pub(in crate::borrow_check) fn add_lifetime_bound_suggestion_to_diagnostic(
         &self,
-        tcx: TyCtxt<'tcx>,
         err: &mut DiagnosticBuilder<'_>,
         category: &ConstraintCategory,
         span: Span,
         region_name: &RegionName,
     ) {
         if let ConstraintCategory::OpaqueType = category {
-            if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) {
-                let suggestable_name = if region_name.was_named() {
-                    region_name.to_string()
-                } else {
-                    "'_".to_string()
-                };
+            let suggestable_name =
+                if region_name.was_named() { region_name.to_string() } else { "'_".to_string() };
 
-                err.span_suggestion(
-                    span,
-                    &format!(
-                        "you can add a bound to the {}to make it last less than \
-                             `'static` and match `{}`",
-                        category.description(),
-                        region_name,
-                    ),
-                    format!("{} + {}", snippet, suggestable_name),
-                    Applicability::Unspecified,
-                );
-            }
+            let msg = format!(
+                "you can add a bound to the {}to make it last less than `'static` and match `{}`",
+                category.description(),
+                region_name,
+            );
+
+            err.span_suggestion_verbose(
+                span.shrink_to_hi(),
+                &msg,
+                format!(" + {}", suggestable_name),
+                Applicability::Unspecified,
+            );
         }
     }
 }
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 0b182d42287..72d20644fe8 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -17,7 +17,7 @@ use rustc_middle::ty::layout::{self, TyAndLayout};
 use rustc_middle::ty::{
     self, fold::BottomUpFolder, query::TyCtxtAt, subst::SubstsRef, Ty, TyCtxt, TypeFoldable,
 };
-use rustc_span::source_map::DUMMY_SP;
+use rustc_span::{source_map::DUMMY_SP, Span};
 use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Size, TargetDataLayout};
 
 use super::{
@@ -256,7 +256,7 @@ pub(super) fn mir_assign_valid_types<'tcx>(
 /// or compute the layout.
 #[cfg_attr(not(debug_assertions), inline(always))]
 pub(super) fn from_known_layout<'tcx>(
-    tcx: TyCtxt<'tcx>,
+    tcx: TyCtxtAt<'tcx>,
     known_layout: Option<TyAndLayout<'tcx>>,
     compute: impl FnOnce() -> InterpResult<'tcx, TyAndLayout<'tcx>>,
 ) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
@@ -265,12 +265,14 @@ pub(super) fn from_known_layout<'tcx>(
         Some(known_layout) => {
             if cfg!(debug_assertions) {
                 let check_layout = compute()?;
-                assert!(
-                    mir_assign_valid_types(tcx, check_layout, known_layout),
-                    "expected type differs from actual type.\nexpected: {:?}\nactual: {:?}",
-                    known_layout.ty,
-                    check_layout.ty,
-                );
+                if !mir_assign_valid_types(tcx.tcx, check_layout, known_layout) {
+                    span_bug!(
+                        tcx.span,
+                        "expected type differs from actual type.\nexpected: {:?}\nactual: {:?}",
+                        known_layout.ty,
+                        check_layout.ty,
+                    );
+                }
             }
             Ok(known_layout)
         }
@@ -295,6 +297,12 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     }
 
     #[inline(always)]
+    pub fn set_span(&mut self, span: Span) {
+        self.tcx.span = span;
+        self.memory.tcx.span = span;
+    }
+
+    #[inline(always)]
     pub fn force_ptr(
         &self,
         scalar: Scalar<M::PointerTag>,
@@ -444,7 +452,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // have to support that case (mostly by skipping all caching).
         match frame.locals.get(local).and_then(|state| state.layout.get()) {
             None => {
-                let layout = from_known_layout(self.tcx.tcx, layout, || {
+                let layout = from_known_layout(self.tcx, layout, || {
                     let local_ty = frame.body.local_decls[local].ty;
                     let local_ty =
                         self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty);
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index 03614b2803f..3741f31927e 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -529,7 +529,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             ty::ConstKind::Value(val_val) => val_val,
         };
         // Other cases need layout.
-        let layout = from_known_layout(self.tcx.tcx, layout, || self.layout_of(val.ty))?;
+        let layout = from_known_layout(self.tcx, layout, || self.layout_of(val.ty))?;
         let op = match val_val {
             ConstValue::ByRef { alloc, offset } => {
                 let id = self.tcx.alloc_map.lock().create_memory_alloc(alloc);
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index 716c7c7d933..828df9a0930 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -867,12 +867,14 @@ where
     ) -> InterpResult<'tcx> {
         // We do NOT compare the types for equality, because well-typed code can
         // actually "transmute" `&mut T` to `&T` in an assignment without a cast.
-        assert!(
-            mir_assign_valid_types(self.tcx.tcx, src.layout, dest.layout),
-            "type mismatch when copying!\nsrc: {:?},\ndest: {:?}",
-            src.layout.ty,
-            dest.layout.ty,
-        );
+        if !mir_assign_valid_types(self.tcx.tcx, src.layout, dest.layout) {
+            span_bug!(
+                self.tcx.span,
+                "type mismatch when copying!\nsrc: {:?},\ndest: {:?}",
+                src.layout.ty,
+                dest.layout.ty,
+            );
+        }
 
         // Let us see if the layout is simple so we take a shortcut, avoid force_allocation.
         let src = match self.try_read_immediate(src)? {
diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs
index 407849c2ce2..37740878f70 100644
--- a/src/librustc_mir/interpret/step.rs
+++ b/src/librustc_mir/interpret/step.rs
@@ -78,14 +78,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
         info!("{:?}", stmt);
+        self.set_span(stmt.source_info.span);
 
         use rustc_middle::mir::StatementKind::*;
 
         // Some statements (e.g., box) push new stack frames.
         // We have to record the stack frame number *before* executing the statement.
         let frame_idx = self.cur_frame();
-        self.tcx.span = stmt.source_info.span;
-        self.memory.tcx.span = stmt.source_info.span;
 
         match &stmt.kind {
             Assign(box (place, rvalue)) => self.eval_rvalue_into_place(rvalue, *place)?,
@@ -276,16 +275,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> {
         info!("{:?}", terminator.kind);
-        self.tcx.span = terminator.source_info.span;
-        self.memory.tcx.span = terminator.source_info.span;
-
-        let old_stack = self.cur_frame();
-        let old_bb = self.frame().block;
+        self.set_span(terminator.source_info.span);
 
         self.eval_terminator(terminator)?;
         if !self.stack.is_empty() {
-            // This should change *something*
-            assert!(self.cur_frame() != old_stack || self.frame().block != old_bb);
             if let Some(block) = self.frame().block {
                 info!("// executing {:?}", block);
             }
diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs
index 6ebe5b80370..2d8551b2bbf 100644
--- a/src/librustc_mir/interpret/terminator.rs
+++ b/src/librustc_mir/interpret/terminator.rs
@@ -52,6 +52,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
 
             Call { ref func, ref args, destination, ref cleanup, .. } => {
+                let old_stack = self.cur_frame();
+                let old_bb = self.frame().block;
                 let func = self.eval_operand(func, None)?;
                 let (fn_val, abi) = match func.layout.ty.kind {
                     ty::FnPtr(sig) => {
@@ -64,7 +66,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                         let sig = func.layout.ty.fn_sig(*self.tcx);
                         (FnVal::Instance(self.resolve(def_id, substs)?), sig.abi())
                     }
-                    _ => bug!("invalid callee of type {:?}", func.layout.ty),
+                    _ => span_bug!(
+                        terminator.source_info.span,
+                        "invalid callee of type {:?}",
+                        func.layout.ty
+                    ),
                 };
                 let args = self.eval_operands(args)?;
                 let ret = match destination {
@@ -72,6 +78,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     None => None,
                 };
                 self.eval_fn_call(fn_val, abi, &args[..], ret, *cleanup)?;
+                // Sanity-check that `eval_fn_call` either pushed a new frame or
+                // did a jump to another block.
+                if self.cur_frame() == old_stack && self.frame().block == old_bb {
+                    span_bug!(terminator.source_info.span, "evaluating this call made no progress");
+                }
             }
 
             Drop { location, target, unwind } => {
@@ -116,9 +127,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             | FalseEdges { .. }
             | FalseUnwind { .. }
             | Yield { .. }
-            | GeneratorDrop => {
-                bug!("{:#?} should have been eliminated by MIR pass", terminator.kind)
-            }
+            | GeneratorDrop => span_bug!(
+                terminator.source_info.span,
+                "{:#?} should have been eliminated by MIR pass",
+                terminator.kind
+            ),
         }
 
         Ok(())
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index 1032ff413af..d8ceda96a25 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -191,7 +191,7 @@ use rustc_middle::mir::visit::Visitor as MirVisitor;
 use rustc_middle::mir::{self, Local, Location};
 use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCast};
 use rustc_middle::ty::print::obsolete::DefPathBasedNames;
-use rustc_middle::ty::subst::InternalSubsts;
+use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
 use rustc_middle::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable};
 use rustc_session::config::EntryFnType;
 use smallvec::SmallVec;
@@ -442,9 +442,16 @@ fn check_recursion_limit<'tcx>(
 }
 
 fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
-    let type_length = instance.substs.types().flat_map(|ty| ty.walk()).count();
-    let const_length = instance.substs.consts().flat_map(|ct| ct.ty.walk()).count();
-    debug!(" => type length={}, const length={}", type_length, const_length);
+    let type_length = instance
+        .substs
+        .iter()
+        .flat_map(|&arg| arg.walk())
+        .filter(|arg| match arg.unpack() {
+            GenericArgKind::Type(_) | GenericArgKind::Const(_) => true,
+            GenericArgKind::Lifetime(_) => false,
+        })
+        .count();
+    debug!(" => type length={}", type_length);
 
     // Rust code can easily create exponentially-long types using only a
     // polynomial recursion depth. Even with the default recursion
@@ -453,11 +460,7 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
     //
     // Bail out in these cases to avoid that bad user experience.
     let type_length_limit = *tcx.sess.type_length_limit.get();
-    // We include the const length in the type length, as it's better
-    // to be overly conservative.
-    // FIXME(const_generics): we should instead uniformly walk through `substs`,
-    // ignoring lifetimes.
-    if type_length + const_length > type_length_limit {
+    if type_length > type_length_limit {
         // The instance name is already known to be too long for rustc.
         // Show only the first and last 32 characters to avoid blasting
         // the user's terminal with thousands of lines of type-name.
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index c7f63d24c28..25719d037f9 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -425,8 +425,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
     }
 
     fn eval_constant(&mut self, c: &Constant<'tcx>, source_info: SourceInfo) -> Option<OpTy<'tcx>> {
-        self.ecx.tcx.span = c.span;
-
         // FIXME we need to revisit this for #67176
         if c.needs_subst() {
             return None;
@@ -435,6 +433,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         match self.ecx.eval_const_to_op(c.literal, None) {
             Ok(op) => Some(op),
             Err(error) => {
+                // Make sure errors point at the constant.
+                self.ecx.set_span(c.span);
                 let err = error_to_const_error(&self.ecx, error);
                 if let Some(lint_root) = self.lint_root(source_info) {
                     let lint_only = match c.literal.val {
@@ -820,6 +820,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
     fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) {
         trace!("visit_statement: {:?}", statement);
         let source_info = statement.source_info;
+        self.ecx.set_span(source_info.span);
         self.source_info = Some(source_info);
         if let StatementKind::Assign(box (place, ref mut rval)) = statement.kind {
             let place_ty: Ty<'tcx> = place.ty(&self.local_decls, self.tcx).ty;
@@ -870,6 +871,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
 
     fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) {
         let source_info = terminator.source_info;
+        self.ecx.set_span(source_info.span);
         self.source_info = Some(source_info);
         self.super_terminator(terminator, location);
         match &mut terminator.kind {
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index c5b366ef572..8f7a1b948e3 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -2,6 +2,7 @@ use rustc_attr as attr;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::mir::*;
+use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{self, adjustment::PointerCast, Predicate, Ty, TyCtxt};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
@@ -92,7 +93,15 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) -
 }
 
 fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span, fn_def_id: DefId) -> McfResult {
-    for ty in ty.walk() {
+    for arg in ty.walk() {
+        let ty = match arg.unpack() {
+            GenericArgKind::Type(ty) => ty,
+
+            // No constraints on lifetimes or constants, except potentially
+            // constants' types, but `walk` will get to them as well.
+            GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue,
+        };
+
         match ty.kind {
             ty::Ref(_, _, hir::Mutability::Mut) => {
                 if !feature_allowed(tcx, fn_def_id, sym::const_mut_refs) {
diff --git a/src/librustc_passes/layout_test.rs b/src/librustc_passes/layout_test.rs
index 22ce909083d..dbc39169f2b 100644
--- a/src/librustc_passes/layout_test.rs
+++ b/src/librustc_passes/layout_test.rs
@@ -85,7 +85,7 @@ impl LayoutTest<'tcx> {
                         sym::debug => {
                             self.tcx.sess.span_err(
                                 item.span,
-                                &format!("layout debugging for type {:?}: {:#?}", ty, *ty_layout),
+                                &format!("layout_of({:?}) = {:#?}", ty, *ty_layout),
                             );
                         }
 
diff --git a/src/librustc_resolve/def_collector.rs b/src/librustc_resolve/def_collector.rs
index 6253f183cc4..71cedb208fc 100644
--- a/src/librustc_resolve/def_collector.rs
+++ b/src/librustc_resolve/def_collector.rs
@@ -2,6 +2,7 @@ use log::debug;
 use rustc_ast::ast::*;
 use rustc_ast::token::{self, Token};
 use rustc_ast::visit::{self, FnKind};
+use rustc_ast::walk_list;
 use rustc_expand::expand::AstFragment;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::definitions::*;
@@ -117,10 +118,8 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
                 // we must mirror everything that `visit::walk_fn` below does.
                 self.visit_fn_header(&sig.header);
                 visit::walk_fn_decl(self, &sig.decl);
-                if let Some(body) = body {
-                    let closure_def = self.create_def(closure_id, DefPathData::ClosureExpr, span);
-                    self.with_parent(closure_def, |this| this.visit_block(body));
-                }
+                let closure_def = self.create_def(closure_id, DefPathData::ClosureExpr, span);
+                self.with_parent(closure_def, |this| walk_list!(this, visit_block, body));
                 return;
             }
         }
diff --git a/src/librustc_target/spec/aarch64_pc_windows_msvc.rs b/src/librustc_target/spec/aarch64_pc_windows_msvc.rs
index 7a46c7da7c3..8c03f1e8a7e 100644
--- a/src/librustc_target/spec/aarch64_pc_windows_msvc.rs
+++ b/src/librustc_target/spec/aarch64_pc_windows_msvc.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, PanicStrategy, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::windows_msvc_base::opts();
@@ -6,9 +6,6 @@ pub fn target() -> TargetResult {
     base.has_elf_tls = true;
     base.features = "+neon,+fp-armv8".to_string();
 
-    // FIXME: this shouldn't be panic=abort, it should be panic=unwind
-    base.panic_strategy = PanicStrategy::Abort;
-
     Ok(Target {
         llvm_target: "aarch64-pc-windows-msvc".to_string(),
         target_endian: "little".to_string(),
diff --git a/src/librustc_target/spec/aarch64_uwp_windows_msvc.rs b/src/librustc_target/spec/aarch64_uwp_windows_msvc.rs
index a793860260c..6a8d148259a 100644
--- a/src/librustc_target/spec/aarch64_uwp_windows_msvc.rs
+++ b/src/librustc_target/spec/aarch64_uwp_windows_msvc.rs
@@ -1,13 +1,10 @@
-use crate::spec::{LinkerFlavor, PanicStrategy, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::windows_uwp_msvc_base::opts();
     base.max_atomic_width = Some(64);
     base.has_elf_tls = true;
 
-    // FIXME: this shouldn't be panic=abort, it should be panic=unwind
-    base.panic_strategy = PanicStrategy::Abort;
-
     Ok(Target {
         llvm_target: "aarch64-pc-windows-msvc".to_string(),
         target_endian: "little".to_string(),
diff --git a/src/librustc_trait_selection/traits/coherence.rs b/src/librustc_trait_selection/traits/coherence.rs
index a642ae98231..f1311382c54 100644
--- a/src/librustc_trait_selection/traits/coherence.rs
+++ b/src/librustc_trait_selection/traits/coherence.rs
@@ -14,6 +14,7 @@ use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::symbol::sym;
 use rustc_span::DUMMY_SP;
+use std::iter;
 
 /// Whether we do the orphan check relative to this crate or
 /// to some remote crate.
@@ -378,26 +379,36 @@ fn orphan_check_trait_ref<'tcx>(
         ty: Ty<'tcx>,
         in_crate: InCrate,
     ) -> Vec<Ty<'tcx>> {
-        if fundamental_ty(ty) && ty_is_non_local(ty, in_crate).is_some() {
-            ty.walk_shallow().flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)).collect()
-        } else {
-            vec![ty]
+        // FIXME(eddyb) figure out if this is redundant with `ty_is_non_local`,
+        // or maybe if this should be calling `ty_is_non_local_constructor`.
+        if ty_is_non_local(tcx, ty, in_crate).is_some() {
+            if let Some(inner_tys) = fundamental_ty_inner_tys(tcx, ty) {
+                return inner_tys
+                    .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate))
+                    .collect();
+            }
         }
+
+        vec![ty]
     }
 
     let mut non_local_spans = vec![];
-    for (i, input_ty) in
-        trait_ref.input_types().flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)).enumerate()
+    for (i, input_ty) in trait_ref
+        .substs
+        .types()
+        .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate))
+        .enumerate()
     {
         debug!("orphan_check_trait_ref: check ty `{:?}`", input_ty);
-        let non_local_tys = ty_is_non_local(input_ty, in_crate);
+        let non_local_tys = ty_is_non_local(tcx, input_ty, in_crate);
         if non_local_tys.is_none() {
             debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty);
             return Ok(());
         } else if let ty::Param(_) = input_ty.kind {
             debug!("orphan_check_trait_ref: uncovered ty: `{:?}`", input_ty);
             let local_type = trait_ref
-                .input_types()
+                .substs
+                .types()
                 .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate))
                 .find(|ty| ty_is_non_local_constructor(ty, in_crate).is_none());
 
@@ -416,30 +427,53 @@ fn orphan_check_trait_ref<'tcx>(
     Err(OrphanCheckErr::NonLocalInputType(non_local_spans))
 }
 
-fn ty_is_non_local<'t>(ty: Ty<'t>, in_crate: InCrate) -> Option<Vec<Ty<'t>>> {
+fn ty_is_non_local(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, in_crate: InCrate) -> Option<Vec<Ty<'tcx>>> {
     match ty_is_non_local_constructor(ty, in_crate) {
         Some(ty) => {
-            if !fundamental_ty(ty) {
-                Some(vec![ty])
-            } else {
-                let tys: Vec<_> = ty
-                    .walk_shallow()
-                    .filter_map(|t| ty_is_non_local(t, in_crate))
-                    .flat_map(|i| i)
+            if let Some(inner_tys) = fundamental_ty_inner_tys(tcx, ty) {
+                let tys: Vec<_> = inner_tys
+                    .filter_map(|ty| ty_is_non_local(tcx, ty, in_crate))
+                    .flatten()
                     .collect();
                 if tys.is_empty() { None } else { Some(tys) }
+            } else {
+                Some(vec![ty])
             }
         }
         None => None,
     }
 }
 
-fn fundamental_ty(ty: Ty<'_>) -> bool {
-    match ty.kind {
-        ty::Ref(..) => true,
-        ty::Adt(def, _) => def.is_fundamental(),
-        _ => false,
-    }
+/// For `#[fundamental]` ADTs and `&T` / `&mut T`, returns `Some` with the
+/// type parameters of the ADT, or `T`, respectively. For non-fundamental
+/// types, returns `None`.
+fn fundamental_ty_inner_tys(
+    tcx: TyCtxt<'tcx>,
+    ty: Ty<'tcx>,
+) -> Option<impl Iterator<Item = Ty<'tcx>>> {
+    let (first_ty, rest_tys) = match ty.kind {
+        ty::Ref(_, ty, _) => (ty, ty::subst::InternalSubsts::empty().types()),
+        ty::Adt(def, substs) if def.is_fundamental() => {
+            let mut types = substs.types();
+
+            // FIXME(eddyb) actually validate `#[fundamental]` up-front.
+            match types.next() {
+                None => {
+                    tcx.sess.span_err(
+                        tcx.def_span(def.did),
+                        "`#[fundamental]` requires at least one type parameter",
+                    );
+
+                    return None;
+                }
+
+                Some(first_ty) => (first_ty, types),
+            }
+        }
+        _ => return None,
+    };
+
+    Some(iter::once(first_ty).chain(rest_tys))
 }
 
 fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool {
@@ -451,6 +485,7 @@ fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool {
     }
 }
 
+// FIXME(eddyb) this can just return `bool` as it always returns `Some(ty)` or `None`.
 fn ty_is_non_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> Option<Ty<'_>> {
     debug!("ty_is_non_local_constructor({:?})", ty);
 
diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
index fcec29aaa8e..a8fc56d8509 100644
--- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
@@ -22,7 +22,8 @@ use std::fmt;
 use super::InferCtxtPrivExt;
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
 
-crate trait InferCtxtExt<'tcx> {
+// This trait is public to expose the diagnostics methods to clippy.
+pub trait InferCtxtExt<'tcx> {
     fn suggest_restricting_param_bound(
         &self,
         err: &mut DiagnosticBuilder<'_>,
diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs
index 09a33120ba7..49a4b96f8b7 100644
--- a/src/librustc_trait_selection/traits/fulfill.rs
+++ b/src/librustc_trait_selection/traits/fulfill.rs
@@ -536,18 +536,17 @@ fn trait_ref_type_vars<'a, 'tcx>(
     selcx: &mut SelectionContext<'a, 'tcx>,
     trait_ref: ty::PolyTraitRef<'tcx>,
 ) -> Vec<TyOrConstInferVar<'tcx>> {
-    trait_ref
+    selcx
+        .infcx()
+        .resolve_vars_if_possible(&trait_ref)
         .skip_binder() // ok b/c this check doesn't care about regions
-        // FIXME(eddyb) walk over `GenericArg` to support const infer vars.
-        .input_types()
-        .map(|ty| selcx.infcx().resolve_vars_if_possible(&ty))
-        // FIXME(eddyb) try using `maybe_walk` to skip *all* subtrees that
-        // don't contain inference variables, not just the outermost level.
-        // FIXME(eddyb) use `has_infer_types_or_const`.
-        .filter(|ty| ty.has_infer_types())
-        .flat_map(|ty| ty.walk())
-        // FIXME(eddyb) use `TyOrConstInferVar::maybe_from_generic_arg`.
-        .filter_map(TyOrConstInferVar::maybe_from_ty)
+        .substs
+        .iter()
+        // FIXME(eddyb) try using `skip_current_subtree` to skip everything that
+        // doesn't contain inference variables, not just the outermost level.
+        .filter(|arg| arg.has_infer_types_or_consts())
+        .flat_map(|arg| arg.walk())
+        .filter_map(TyOrConstInferVar::maybe_from_generic_arg)
         .collect()
 }
 
diff --git a/src/librustc_trait_selection/traits/object_safety.rs b/src/librustc_trait_selection/traits/object_safety.rs
index 20b3fa908d2..d9a5b68dc1e 100644
--- a/src/librustc_trait_selection/traits/object_safety.rs
+++ b/src/librustc_trait_selection/traits/object_safety.rs
@@ -16,7 +16,7 @@ use crate::traits::{self, Obligation, ObligationCause};
 use rustc_errors::{Applicability, FatalError};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::subst::{InternalSubsts, Subst};
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst};
 use rustc_middle::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
 use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
 use rustc_span::symbol::Symbol;
@@ -234,7 +234,7 @@ fn predicates_reference_self(
         tcx.predicates_of(trait_def_id)
     };
     let self_ty = tcx.types.self_param;
-    let has_self_ty = |t: Ty<'_>| t.walk().any(|t| t == self_ty);
+    let has_self_ty = |arg: &GenericArg<'_>| arg.walk().any(|arg| arg == self_ty.into());
     predicates
         .predicates
         .iter()
@@ -243,7 +243,7 @@ fn predicates_reference_self(
             match predicate {
                 ty::Predicate::Trait(ref data, _) => {
                     // In the case of a trait predicate, we can skip the "self" type.
-                    if data.skip_binder().input_types().skip(1).any(has_self_ty) {
+                    if data.skip_binder().trait_ref.substs[1..].iter().any(has_self_ty) {
                         Some(sp)
                     } else {
                         None
@@ -262,12 +262,8 @@ fn predicates_reference_self(
                     //
                     // This is ALT2 in issue #56288, see that for discussion of the
                     // possible alternatives.
-                    if data
-                        .skip_binder()
-                        .projection_ty
-                        .trait_ref(tcx)
-                        .input_types()
-                        .skip(1)
+                    if data.skip_binder().projection_ty.trait_ref(tcx).substs[1..]
+                        .iter()
                         .any(has_self_ty)
                     {
                         Some(sp)
@@ -725,19 +721,17 @@ fn contains_illegal_self_type_reference<'tcx>(
     // without knowing what `Self` is.
 
     let mut supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>> = None;
-    let mut error = false;
     let self_ty = tcx.types.self_param;
-    ty.maybe_walk(|ty| {
-        match ty.kind {
-            ty::Param(_) => {
-                if ty == self_ty {
-                    error = true;
-                }
 
-                false // no contained types to walk
-            }
+    let mut walker = ty.walk();
+    while let Some(arg) = walker.next() {
+        if arg == self_ty.into() {
+            return true;
+        }
 
-            ty::Projection(ref data) => {
+        // Special-case projections (everything else is walked normally).
+        if let GenericArgKind::Type(ty) = arg.unpack() {
+            if let ty::Projection(ref data) = ty.kind {
                 // This is a projected type `<Foo as SomeTrait>::X`.
 
                 // Compute supertraits of current trait lazily.
@@ -759,17 +753,18 @@ fn contains_illegal_self_type_reference<'tcx>(
                     supertraits.as_ref().unwrap().contains(&projection_trait_ref);
 
                 if is_supertrait_of_current_trait {
-                    false // do not walk contained types, do not report error, do collect $200
-                } else {
-                    true // DO walk contained types, POSSIBLY reporting an error
+                    // Do not walk contained types, do not report error, do collect $200.
+                    walker.skip_current_subtree();
                 }
-            }
 
-            _ => true, // walk contained types, if any
+                // DO walk contained types, POSSIBLY reporting an error.
+            }
         }
-    });
 
-    error
+        // Walk contained types, if any.
+    }
+
+    false
 }
 
 pub fn provide(providers: &mut ty::query::Providers<'_>) {
diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs
index 3d95824cdf0..84c264f06db 100644
--- a/src/librustc_trait_selection/traits/select.rs
+++ b/src/librustc_trait_selection/traits/select.rs
@@ -44,7 +44,7 @@ use rustc_index::bit_set::GrowableBitSet;
 use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
 use rustc_middle::ty::fast_reject;
 use rustc_middle::ty::relate::TypeRelation;
-use rustc_middle::ty::subst::{Subst, SubstsRef};
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
 use rustc_middle::ty::{
     self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
 };
@@ -652,7 +652,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &mut self,
         stack: &TraitObligationStack<'o, 'tcx>,
     ) -> Result<EvaluationResult, OverflowError> {
-        // In intercrate mode, whenever any of the types are unbound,
+        // In intercrate mode, whenever any of the generics are unbound,
         // there can always be an impl. Even if there are no impls in
         // this crate, perhaps the type would be unified with
         // something from another crate that does provide an impl.
@@ -677,7 +677,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // terms of `Fn` etc, but we could probably make this more
         // precise still.
         let unbound_input_types =
-            stack.fresh_trait_ref.skip_binder().input_types().any(|ty| ty.is_fresh());
+            stack.fresh_trait_ref.skip_binder().substs.types().any(|ty| ty.is_fresh());
         // This check was an imperfect workaround for a bug in the old
         // intercrate mode; it should be removed when that goes away.
         if unbound_input_types && self.intercrate {
@@ -1242,9 +1242,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         result: &SelectionResult<'tcx, SelectionCandidate<'tcx>>,
     ) -> bool {
         match result {
-            Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => {
-                !trait_ref.skip_binder().input_types().any(|t| t.walk().any(|t_| t_.is_ty_infer()))
-            }
+            Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => !trait_ref.has_local_value(),
             _ => true,
         }
     }
@@ -3048,20 +3046,31 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
             // `Struct<T>` -> `Struct<U>`
             (&ty::Adt(def, substs_a), &ty::Adt(_, substs_b)) => {
-                let fields =
-                    def.all_fields().map(|field| tcx.type_of(field.did)).collect::<Vec<_>>();
-
-                // The last field of the structure has to exist and contain type parameters.
-                let field = if let Some(&field) = fields.last() {
-                    field
-                } else {
-                    return Err(Unimplemented);
+                let maybe_unsizing_param_idx = |arg: GenericArg<'tcx>| match arg.unpack() {
+                    GenericArgKind::Type(ty) => match ty.kind {
+                        ty::Param(p) => Some(p.index),
+                        _ => None,
+                    },
+
+                    // Lifetimes aren't allowed to change during unsizing.
+                    GenericArgKind::Lifetime(_) => None,
+
+                    GenericArgKind::Const(ct) => match ct.val {
+                        ty::ConstKind::Param(p) => Some(p.index),
+                        _ => None,
+                    },
                 };
-                let mut ty_params = GrowableBitSet::new_empty();
+
+                // The last field of the structure has to exist and contain type/const parameters.
+                let (tail_field, prefix_fields) =
+                    def.non_enum_variant().fields.split_last().ok_or(Unimplemented)?;
+                let tail_field_ty = tcx.type_of(tail_field.did);
+
+                let mut unsizing_params = GrowableBitSet::new_empty();
                 let mut found = false;
-                for ty in field.walk() {
-                    if let ty::Param(p) = ty.kind {
-                        ty_params.insert(p.index as usize);
+                for arg in tail_field_ty.walk() {
+                    if let Some(i) = maybe_unsizing_param_idx(arg) {
+                        unsizing_params.insert(i);
                         found = true;
                     }
                 }
@@ -3069,31 +3078,31 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     return Err(Unimplemented);
                 }
 
-                // Replace type parameters used in unsizing with
-                // Error and ensure they do not affect any other fields.
-                // This could be checked after type collection for any struct
-                // with a potentially unsized trailing field.
-                let params = substs_a
-                    .iter()
-                    .enumerate()
-                    .map(|(i, &k)| if ty_params.contains(i) { tcx.types.err.into() } else { k });
-                let substs = tcx.mk_substs(params);
-                for &ty in fields.split_last().unwrap().1 {
-                    if ty.subst(tcx, substs).references_error() {
-                        return Err(Unimplemented);
+                // Ensure none of the other fields mention the parameters used
+                // in unsizing.
+                // FIXME(eddyb) cache this (including computing `unsizing_params`)
+                // by putting it in a query; it would only need the `DefId` as it
+                // looks at declared field types, not anything substituted.
+                for field in prefix_fields {
+                    for arg in tcx.type_of(field.did).walk() {
+                        if let Some(i) = maybe_unsizing_param_idx(arg) {
+                            if unsizing_params.contains(i) {
+                                return Err(Unimplemented);
+                            }
+                        }
                     }
                 }
 
-                // Extract `Field<T>` and `Field<U>` from `Struct<T>` and `Struct<U>`.
-                let inner_source = field.subst(tcx, substs_a);
-                let inner_target = field.subst(tcx, substs_b);
+                // Extract `TailField<T>` and `TailField<U>` from `Struct<T>` and `Struct<U>`.
+                let source_tail = tail_field_ty.subst(tcx, substs_a);
+                let target_tail = tail_field_ty.subst(tcx, substs_b);
 
                 // Check that the source struct with the target's
-                // unsized parameters is equal to the target.
-                let params = substs_a.iter().enumerate().map(|(i, &k)| {
-                    if ty_params.contains(i) { substs_b.type_at(i).into() } else { k }
-                });
-                let new_struct = tcx.mk_adt(def, tcx.mk_substs(params));
+                // unsizing parameters is equal to the target.
+                let substs = tcx.mk_substs(substs_a.iter().enumerate().map(|(i, &k)| {
+                    if unsizing_params.contains(i as u32) { substs_b[i] } else { k }
+                }));
+                let new_struct = tcx.mk_adt(def, substs);
                 let InferOk { obligations, .. } = self
                     .infcx
                     .at(&obligation.cause, obligation.param_env)
@@ -3101,15 +3110,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     .map_err(|_| Unimplemented)?;
                 nested.extend(obligations);
 
-                // Construct the nested `Field<T>: Unsize<Field<U>>` predicate.
+                // Construct the nested `TailField<T>: Unsize<TailField<U>>` predicate.
                 nested.push(predicate_for_trait_def(
                     tcx,
                     obligation.param_env,
                     obligation.cause.clone(),
                     obligation.predicate.def_id(),
                     obligation.recursion_depth + 1,
-                    inner_source,
-                    &[inner_target.into()],
+                    source_tail,
+                    &[target_tail.into()],
                 ));
             }
 
@@ -3253,15 +3262,31 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // substitution if we find that any of the input types, when
         // simplified, do not match.
 
-        obligation.predicate.skip_binder().input_types().zip(impl_trait_ref.input_types()).any(
-            |(obligation_ty, impl_ty)| {
-                let simplified_obligation_ty =
-                    fast_reject::simplify_type(self.tcx(), obligation_ty, true);
-                let simplified_impl_ty = fast_reject::simplify_type(self.tcx(), impl_ty, false);
-
-                simplified_obligation_ty.is_some()
-                    && simplified_impl_ty.is_some()
-                    && simplified_obligation_ty != simplified_impl_ty
+        obligation.predicate.skip_binder().trait_ref.substs.iter().zip(impl_trait_ref.substs).any(
+            |(obligation_arg, impl_arg)| {
+                match (obligation_arg.unpack(), impl_arg.unpack()) {
+                    (GenericArgKind::Type(obligation_ty), GenericArgKind::Type(impl_ty)) => {
+                        let simplified_obligation_ty =
+                            fast_reject::simplify_type(self.tcx(), obligation_ty, true);
+                        let simplified_impl_ty =
+                            fast_reject::simplify_type(self.tcx(), impl_ty, false);
+
+                        simplified_obligation_ty.is_some()
+                            && simplified_impl_ty.is_some()
+                            && simplified_obligation_ty != simplified_impl_ty
+                    }
+                    (GenericArgKind::Lifetime(_), GenericArgKind::Lifetime(_)) => {
+                        // Lifetimes can never cause a rejection.
+                        false
+                    }
+                    (GenericArgKind::Const(_), GenericArgKind::Const(_)) => {
+                        // Conservatively ignore consts (i.e. assume they might
+                        // unify later) until we have `fast_reject` support for
+                        // them (if we'll ever need it, even).
+                        false
+                    }
+                    _ => unreachable!(),
+                }
             },
         )
     }
diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs
index 1eb41e0b4d1..6b38749e1e7 100644
--- a/src/librustc_trait_selection/traits/wf.rs
+++ b/src/librustc_trait_selection/traits/wf.rs
@@ -4,7 +4,7 @@ use crate::traits::{self, AssocTypeBoundData};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items;
-use rustc_middle::ty::subst::SubstsRef;
+use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
 use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::Span;
@@ -391,9 +391,21 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
     /// is WF. Returns false if `ty0` is an unresolved type variable,
     /// in which case we are not able to simplify at all.
     fn compute(&mut self, ty0: Ty<'tcx>) -> bool {
-        let mut subtys = ty0.walk();
+        let mut walker = ty0.walk();
         let param_env = self.param_env;
-        while let Some(ty) = subtys.next() {
+        while let Some(arg) = walker.next() {
+            let ty = match arg.unpack() {
+                GenericArgKind::Type(ty) => ty,
+
+                // No WF constraints for lifetimes being present, any outlives
+                // obligations are handled by the parent (e.g. `ty::Ref`).
+                GenericArgKind::Lifetime(_) => continue,
+
+                // FIXME(eddyb) this is wrong and needs to be replaced
+                // (see https://github.com/rust-lang/rust/pull/70107).
+                GenericArgKind::Const(_) => continue,
+            };
+
             match ty.kind {
                 ty::Bool
                 | ty::Char
@@ -417,6 +429,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
 
                 ty::Array(subty, len) => {
                     self.require_sized(subty, traits::SliceOrArrayElem);
+                    // FIXME(eddyb) handle `GenericArgKind::Const` above instead.
                     self.compute_array_len(*len);
                 }
 
@@ -433,7 +446,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                 }
 
                 ty::Projection(data) => {
-                    subtys.skip_current_subtree(); // subtree handled by compute_projection
+                    walker.skip_current_subtree(); // subtree handled by compute_projection
                     self.compute_projection(data);
                 }
 
@@ -504,7 +517,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                     // are not directly inspecting closure types
                     // anyway, except via auto trait matching (which
                     // only inspects the upvar types).
-                    subtys.skip_current_subtree(); // subtree handled by compute_projection
+                    walker.skip_current_subtree(); // subtree handled by compute_projection
                     for upvar_ty in substs.as_closure().upvar_tys() {
                         self.compute(upvar_ty);
                     }
diff --git a/src/librustc_traits/lowering/environment.rs b/src/librustc_traits/lowering/environment.rs
index 28d5d25dd1b..612ab9b70eb 100644
--- a/src/librustc_traits/lowering/environment.rs
+++ b/src/librustc_traits/lowering/environment.rs
@@ -3,6 +3,7 @@ use rustc_hir::def_id::DefId;
 use rustc_middle::traits::{
     Clause, Clauses, DomainGoal, Environment, FromEnv, ProgramClause, ProgramClauseCategory,
 };
+use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 
 struct ClauseVisitor<'a, 'tcx> {
@@ -210,7 +211,8 @@ crate fn environment(tcx: TyCtxt<'_>, def_id: DefId) -> Environment<'_> {
         _ => NodeKind::Other,
     };
 
-    let mut input_tys = FxHashSet::default();
+    // FIXME(eddyb) isn't the unordered nature of this a hazard?
+    let mut inputs = FxHashSet::default();
 
     match node_kind {
         // In a trait impl, we assume that the header trait ref and all its
@@ -218,14 +220,14 @@ crate fn environment(tcx: TyCtxt<'_>, def_id: DefId) -> Environment<'_> {
         NodeKind::TraitImpl => {
             let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl");
 
-            input_tys.extend(trait_ref.input_types().flat_map(|ty| ty.walk()));
+            inputs.extend(trait_ref.substs.iter().flat_map(|&arg| arg.walk()));
         }
 
         // In an inherent impl, we assume that the receiver type and all its
         // constituents are well-formed.
         NodeKind::InherentImpl => {
             let self_ty = tcx.type_of(def_id);
-            input_tys.extend(self_ty.walk());
+            inputs.extend(self_ty.walk());
         }
 
         // In an fn, we assume that the arguments and all their constituents are
@@ -234,16 +236,27 @@ crate fn environment(tcx: TyCtxt<'_>, def_id: DefId) -> Environment<'_> {
             let fn_sig = tcx.fn_sig(def_id);
             let fn_sig = tcx.liberate_late_bound_regions(def_id, &fn_sig);
 
-            input_tys.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk()));
+            inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk()));
         }
 
         NodeKind::Other => (),
     }
 
     let clauses = clauses.chain(
-        input_tys
+        inputs
             .into_iter()
-            .map(|ty| DomainGoal::FromEnv(FromEnv::Ty(ty)))
+            .filter_map(|arg| {
+                match arg.unpack() {
+                    GenericArgKind::Type(ty) => Some(FromEnv::Ty(ty)),
+
+                    // FIXME(eddyb) no WF conditions from lifetimes?
+                    GenericArgKind::Lifetime(_) => None,
+
+                    // FIXME(eddyb) support const generics in Chalk
+                    GenericArgKind::Const(_) => None,
+                }
+            })
+            .map(DomainGoal::FromEnv)
             .map(|domain_goal| domain_goal.into_program_clause())
             .map(Clause::Implies),
     );
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index c3ebcbfc832..ed7ec1c3b10 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -737,8 +737,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         let default_needs_object_self = |param: &ty::GenericParamDef| {
             if let GenericParamDefKind::Type { has_default, .. } = param.kind {
                 if is_object && has_default {
+                    let default_ty = tcx.at(span).type_of(param.def_id);
                     let self_param = tcx.types.self_param;
-                    if tcx.at(span).type_of(param.def_id).walk().any(|ty| ty == self_param) {
+                    if default_ty.walk().any(|arg| arg == self_param.into()) {
                         // There is no suitable inference default for a type parameter
                         // that references self, in an object type.
                         return true;
@@ -1617,7 +1618,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     ty::Predicate::Projection(pred) => {
                         // A `Self` within the original bound will be substituted with a
                         // `trait_object_dummy_self`, so check for that.
-                        let references_self = pred.skip_binder().ty.walk().any(|t| t == dummy_self);
+                        let references_self =
+                            pred.skip_binder().ty.walk().any(|arg| arg == dummy_self.into());
 
                         // If the projection output contains `Self`, force the user to
                         // elaborate it explicitly to avoid a lot of complexity.
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 5a97a2af120..ff3493eb6de 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -563,30 +563,30 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         while !queue.is_empty() {
             let obligation = queue.remove(0);
             debug!("coerce_unsized resolve step: {:?}", obligation);
-            let trait_ref = match obligation.predicate {
-                ty::Predicate::Trait(ref tr, _) if traits.contains(&tr.def_id()) => {
-                    if unsize_did == tr.def_id() {
-                        let sty = &tr.skip_binder().input_types().nth(1).unwrap().kind;
-                        if let ty::Tuple(..) = sty {
+            let trait_pred = match obligation.predicate {
+                ty::Predicate::Trait(trait_pred, _) if traits.contains(&trait_pred.def_id()) => {
+                    if unsize_did == trait_pred.def_id() {
+                        let unsize_ty = trait_pred.skip_binder().trait_ref.substs[1].expect_ty();
+                        if let ty::Tuple(..) = unsize_ty.kind {
                             debug!("coerce_unsized: found unsized tuple coercion");
                             has_unsized_tuple_coercion = true;
                         }
                     }
-                    *tr
+                    trait_pred
                 }
                 _ => {
                     coercion.obligations.push(obligation);
                     continue;
                 }
             };
-            match selcx.select(&obligation.with(trait_ref)) {
+            match selcx.select(&obligation.with(trait_pred)) {
                 // Uncertain or unimplemented.
                 Ok(None) => {
-                    if trait_ref.def_id() == unsize_did {
-                        let trait_ref = self.resolve_vars_if_possible(&trait_ref);
-                        let self_ty = trait_ref.skip_binder().self_ty();
-                        let unsize_ty = trait_ref.skip_binder().input_types().nth(1).unwrap();
-                        debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_ref);
+                    if trait_pred.def_id() == unsize_did {
+                        let trait_pred = self.resolve_vars_if_possible(&trait_pred);
+                        let self_ty = trait_pred.skip_binder().self_ty();
+                        let unsize_ty = trait_pred.skip_binder().trait_ref.substs[1].expect_ty();
+                        debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_pred);
                         match (&self_ty.kind, &unsize_ty.kind) {
                             (ty::Infer(ty::TyVar(v)), ty::Dynamic(..))
                                 if self.type_var_is_sized(*v) =>
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 293c4feac62..eebc34d3db8 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -102,6 +102,7 @@ use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::lang_items;
 use rustc_hir::{ExprKind, GenericArg, HirIdMap, Item, ItemKind, Node, PatKind, QPath};
+use rustc_index::bit_set::BitSet;
 use rustc_index::vec::Idx;
 use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
 use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
@@ -1767,7 +1768,7 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
             let def_id = tcx.hir().local_def_id(it.hir_id);
             let pty_ty = tcx.type_of(def_id);
             let generics = tcx.generics_of(def_id);
-            check_bounds_are_used(tcx, &generics, pty_ty);
+            check_type_params_are_used(tcx, &generics, pty_ty);
         }
         hir::ItemKind::ForeignMod(ref m) => {
             check_abi(tcx, it.span, m.abi);
@@ -4139,20 +4140,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // `FulfillmentError`.
                 let mut referenced_in = final_arg_types
                     .iter()
-                    .map(|(i, checked_ty, _)| (i, checked_ty))
-                    .chain(final_arg_types.iter().map(|(i, _, coerced_ty)| (i, coerced_ty)))
+                    .map(|&(i, checked_ty, _)| (i, checked_ty))
+                    .chain(final_arg_types.iter().map(|&(i, _, coerced_ty)| (i, coerced_ty)))
                     .flat_map(|(i, ty)| {
-                        let ty = self.resolve_vars_if_possible(ty);
+                        let ty = self.resolve_vars_if_possible(&ty);
                         // We walk the argument type because the argument's type could have
                         // been `Option<T>`, but the `FulfillmentError` references `T`.
-                        ty.walk()
-                            .filter(|&ty| ty == predicate.skip_binder().self_ty())
-                            .map(move |_| *i)
+                        if ty.walk().any(|arg| arg == predicate.skip_binder().self_ty().into()) {
+                            Some(i)
+                        } else {
+                            None
+                        }
                     })
                     .collect::<Vec<_>>();
 
                 // Both checked and coerced types could have matched, thus we need to remove
                 // duplicates.
+                referenced_in.sort();
                 referenced_in.dedup();
 
                 if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) {
@@ -5744,43 +5748,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 }
 
-pub fn check_bounds_are_used<'tcx>(tcx: TyCtxt<'tcx>, generics: &ty::Generics, ty: Ty<'tcx>) {
-    let own_counts = generics.own_counts();
-    debug!(
-        "check_bounds_are_used(n_tys={}, n_cts={}, ty={:?})",
-        own_counts.types, own_counts.consts, ty
-    );
+fn check_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, generics: &ty::Generics, ty: Ty<'tcx>) {
+    debug!("check_type_params_are_used(generics={:?}, ty={:?})", generics, ty);
+
+    assert_eq!(generics.parent, None);
 
-    if own_counts.types == 0 {
+    if generics.own_counts().types == 0 {
         return;
     }
 
-    // Make a vector of booleans initially `false`; set to `true` when used.
-    let mut types_used = vec![false; own_counts.types];
+    let mut params_used = BitSet::new_empty(generics.params.len());
 
-    for leaf_ty in ty.walk() {
-        if let ty::Param(ty::ParamTy { index, .. }) = leaf_ty.kind {
-            debug!("found use of ty param num {}", index);
-            types_used[index as usize - own_counts.lifetimes] = true;
-        } else if let ty::Error = leaf_ty.kind {
-            // If there is already another error, do not emit
-            // an error for not using a type parameter.
-            assert!(tcx.sess.has_errors());
-            return;
+    if ty.references_error() {
+        // If there is already another error, do not emit
+        // an error for not using a type parameter.
+        assert!(tcx.sess.has_errors());
+        return;
+    }
+
+    for leaf in ty.walk() {
+        if let GenericArgKind::Type(leaf_ty) = leaf.unpack() {
+            if let ty::Param(param) = leaf_ty.kind {
+                debug!("found use of ty param {:?}", param);
+                params_used.insert(param.index);
+            }
         }
     }
 
-    let types = generics.params.iter().filter(|param| match param.kind {
-        ty::GenericParamDefKind::Type { .. } => true,
-        _ => false,
-    });
-    for (&used, param) in types_used.iter().zip(types) {
-        if !used {
-            let id = tcx.hir().as_local_hir_id(param.def_id).unwrap();
-            let span = tcx.hir().span(id);
-            struct_span_err!(tcx.sess, span, E0091, "type parameter `{}` is unused", param.name)
+    for param in &generics.params {
+        if !params_used.contains(param.index) {
+            if let ty::GenericParamDefKind::Type { .. } = param.kind {
+                let span = tcx.def_span(param.def_id);
+                struct_span_err!(
+                    tcx.sess,
+                    span,
+                    E0091,
+                    "type parameter `{}` is unused",
+                    param.name,
+                )
                 .span_label(span, "unused type parameter")
                 .emit();
+            }
         }
     }
 }
diff --git a/src/librustc_typeck/outlives/implicit_infer.rs b/src/librustc_typeck/outlives/implicit_infer.rs
index df7c535ff3b..2abca302469 100644
--- a/src/librustc_typeck/outlives/implicit_infer.rs
+++ b/src/librustc_typeck/outlives/implicit_infer.rs
@@ -119,7 +119,15 @@ fn insert_required_predicates_to_be_wf<'tcx>(
     required_predicates: &mut RequiredPredicates<'tcx>,
     explicit_map: &mut ExplicitPredicatesMap<'tcx>,
 ) {
-    for ty in field_ty.walk() {
+    for arg in field_ty.walk() {
+        let ty = match arg.unpack() {
+            GenericArgKind::Type(ty) => ty,
+
+            // No predicates from lifetimes or constants, except potentially
+            // constants' types, but `walk` will get to them as well.
+            GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue,
+        };
+
         match ty.kind {
             // The field is of type &'a T which means that we will have
             // a predicate requirement of T: 'a (T outlives 'a).
@@ -303,7 +311,7 @@ pub fn check_explicit_predicates<'tcx>(
         // 'b`.
         if let Some(self_ty) = ignored_self_ty {
             if let GenericArgKind::Type(ty) = outlives_predicate.0.unpack() {
-                if ty.walk().any(|ty| ty == self_ty) {
+                if ty.walk().any(|arg| arg == self_ty.into()) {
                     debug!("skipping self ty = {:?}", &ty);
                     continue;
                 }
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 73df844a91b..eb8aec708a6 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -315,25 +315,28 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
         tcx: TyCtxt<'tcx>,
         pred: ty::Predicate<'tcx>,
     ) -> FxHashSet<GenericParamDef> {
-        pred.walk_tys()
-            .flat_map(|t| {
-                let mut regions = FxHashSet::default();
-                tcx.collect_regions(&t, &mut regions);
-
-                regions.into_iter().flat_map(|r| {
-                    match r {
-                        // We only care about late bound regions, as we need to add them
-                        // to the 'for<>' section
-                        &ty::ReLateBound(_, ty::BoundRegion::BrNamed(_, name)) => {
-                            Some(GenericParamDef {
-                                name: name.to_string(),
-                                kind: GenericParamDefKind::Lifetime,
-                            })
-                        }
-                        &ty::ReVar(_) | &ty::ReEarlyBound(_) | &ty::ReStatic => None,
-                        _ => panic!("Unexpected region type {:?}", r),
-                    }
-                })
+        let regions = match pred {
+            ty::Predicate::Trait(poly_trait_pred, _) => {
+                tcx.collect_referenced_late_bound_regions(&poly_trait_pred)
+            }
+            ty::Predicate::Projection(poly_proj_pred) => {
+                tcx.collect_referenced_late_bound_regions(&poly_proj_pred)
+            }
+            _ => return FxHashSet::default(),
+        };
+
+        regions
+            .into_iter()
+            .filter_map(|br| {
+                match br {
+                    // We only care about named late bound regions, as we need to add them
+                    // to the 'for<>' section
+                    ty::BrNamed(_, name) => Some(GenericParamDef {
+                        name: name.to_string(),
+                        kind: GenericParamDefKind::Lifetime,
+                    }),
+                    _ => None,
+                }
             })
             .collect()
     }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index f4111483902..5c35dc55132 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -84,15 +84,6 @@ impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> {
     }
 }
 
-impl<T, U> Clean<U> for ty::Binder<T>
-where
-    T: Clean<U>,
-{
-    fn clean(&self, cx: &DocContext<'_>) -> U {
-        self.skip_binder().clean(cx)
-    }
-}
-
 impl Clean<ExternalCrate> for CrateNum {
     fn clean(&self, cx: &DocContext<'_>) -> ExternalCrate {
         let root = DefId { krate: *self, index: CRATE_DEF_INDEX };
@@ -305,59 +296,66 @@ impl Clean<GenericBound> for hir::GenericBound<'_> {
     }
 }
 
-impl<'a, 'tcx> Clean<GenericBound> for (&'a ty::TraitRef<'tcx>, Vec<TypeBinding>) {
-    fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
-        let (trait_ref, ref bounds) = *self;
+impl Clean<Type> for (ty::TraitRef<'_>, &[TypeBinding]) {
+    fn clean(&self, cx: &DocContext<'_>) -> Type {
+        let (trait_ref, bounds) = *self;
         inline::record_extern_fqn(cx, trait_ref.def_id, TypeKind::Trait);
         let path = external_path(
             cx,
             cx.tcx.item_name(trait_ref.def_id),
             Some(trait_ref.def_id),
             true,
-            bounds.clone(),
+            bounds.to_vec(),
             trait_ref.substs,
         );
 
         debug!("ty::TraitRef\n  subst: {:?}\n", trait_ref.substs);
 
+        ResolvedPath { path, param_names: None, did: trait_ref.def_id, is_generic: false }
+    }
+}
+
+impl<'tcx> Clean<GenericBound> for ty::TraitRef<'tcx> {
+    fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
+        GenericBound::TraitBound(
+            PolyTrait { trait_: (*self, &[][..]).clean(cx), generic_params: vec![] },
+            hir::TraitBoundModifier::None,
+        )
+    }
+}
+
+impl Clean<GenericBound> for (ty::PolyTraitRef<'_>, &[TypeBinding]) {
+    fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
+        let (poly_trait_ref, bounds) = *self;
+        let poly_trait_ref = poly_trait_ref.lift_to_tcx(cx.tcx).unwrap();
+
         // collect any late bound regions
-        let mut late_bounds = vec![];
-        for ty_s in trait_ref.input_types().skip(1) {
-            if let ty::Tuple(ts) = ty_s.kind {
-                for &ty_s in ts {
-                    if let ty::Ref(ref reg, _, _) = ty_s.expect_ty().kind {
-                        if let &ty::RegionKind::ReLateBound(..) = *reg {
-                            debug!("  hit an ReLateBound {:?}", reg);
-                            if let Some(Lifetime(name)) = reg.clean(cx) {
-                                late_bounds.push(GenericParamDef {
-                                    name,
-                                    kind: GenericParamDefKind::Lifetime,
-                                });
-                            }
-                        }
-                    }
-                }
-            }
-        }
+        let late_bound_regions: Vec<_> = cx
+            .tcx
+            .collect_referenced_late_bound_regions(&poly_trait_ref)
+            .into_iter()
+            .filter_map(|br| match br {
+                ty::BrNamed(_, name) => Some(GenericParamDef {
+                    name: name.to_string(),
+                    kind: GenericParamDefKind::Lifetime,
+                }),
+                _ => None,
+            })
+            .collect();
 
         GenericBound::TraitBound(
             PolyTrait {
-                trait_: ResolvedPath {
-                    path,
-                    param_names: None,
-                    did: trait_ref.def_id,
-                    is_generic: false,
-                },
-                generic_params: late_bounds,
+                trait_: (*poly_trait_ref.skip_binder(), bounds).clean(cx),
+                generic_params: late_bound_regions,
             },
             hir::TraitBoundModifier::None,
         )
     }
 }
 
-impl<'tcx> Clean<GenericBound> for ty::TraitRef<'tcx> {
+impl<'tcx> Clean<GenericBound> for ty::PolyTraitRef<'tcx> {
     fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
-        (self, vec![]).clean(cx)
+        (*self, &[][..]).clean(cx)
     }
 }
 
@@ -495,16 +493,17 @@ impl<'a> Clean<Option<WherePredicate>> for ty::Predicate<'a> {
     }
 }
 
-impl<'a> Clean<WherePredicate> for ty::TraitPredicate<'a> {
+impl<'a> Clean<WherePredicate> for ty::PolyTraitPredicate<'a> {
     fn clean(&self, cx: &DocContext<'_>) -> WherePredicate {
+        let poly_trait_ref = self.map_bound(|pred| pred.trait_ref);
         WherePredicate::BoundPredicate {
-            ty: self.trait_ref.self_ty().clean(cx),
-            bounds: vec![self.trait_ref.clean(cx)],
+            ty: poly_trait_ref.self_ty().clean(cx),
+            bounds: vec![poly_trait_ref.clean(cx)],
         }
     }
 }
 
-impl<'tcx> Clean<WherePredicate> for ty::SubtypePredicate<'tcx> {
+impl<'tcx> Clean<WherePredicate> for ty::PolySubtypePredicate<'tcx> {
     fn clean(&self, _cx: &DocContext<'_>) -> WherePredicate {
         panic!(
             "subtype predicates are an internal rustc artifact \
@@ -514,10 +513,10 @@ impl<'tcx> Clean<WherePredicate> for ty::SubtypePredicate<'tcx> {
 }
 
 impl<'tcx> Clean<Option<WherePredicate>>
-    for ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>
+    for ty::PolyOutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>
 {
     fn clean(&self, cx: &DocContext<'_>) -> Option<WherePredicate> {
-        let ty::OutlivesPredicate(ref a, ref b) = *self;
+        let ty::OutlivesPredicate(a, b) = self.skip_binder();
 
         if let (ty::ReEmpty(_), ty::ReEmpty(_)) = (a, b) {
             return None;
@@ -530,9 +529,9 @@ impl<'tcx> Clean<Option<WherePredicate>>
     }
 }
 
-impl<'tcx> Clean<Option<WherePredicate>> for ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>> {
+impl<'tcx> Clean<Option<WherePredicate>> for ty::PolyOutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>> {
     fn clean(&self, cx: &DocContext<'_>) -> Option<WherePredicate> {
-        let ty::OutlivesPredicate(ref ty, ref lt) = *self;
+        let ty::OutlivesPredicate(ty, lt) = self.skip_binder();
 
         if let ty::ReEmpty(_) = lt {
             return None;
@@ -545,9 +544,10 @@ impl<'tcx> Clean<Option<WherePredicate>> for ty::OutlivesPredicate<Ty<'tcx>, ty:
     }
 }
 
-impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> {
+impl<'tcx> Clean<WherePredicate> for ty::PolyProjectionPredicate<'tcx> {
     fn clean(&self, cx: &DocContext<'_>) -> WherePredicate {
-        WherePredicate::EqPredicate { lhs: self.projection_ty.clean(cx), rhs: self.ty.clean(cx) }
+        let ty::ProjectionPredicate { projection_ty, ty } = *self.skip_binder();
+        WherePredicate::EqPredicate { lhs: projection_ty.clean(cx), rhs: ty.clean(cx) }
     }
 }
 
@@ -1674,7 +1674,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                             }
                         }
 
-                        let bounds = bounds
+                        let bounds: Vec<_> = bounds
                             .predicates
                             .iter()
                             .filter_map(|pred| {
@@ -1703,7 +1703,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                             })
                             .collect();
 
-                        Some((trait_ref.skip_binder(), bounds).clean(cx))
+                        Some((trait_ref, &bounds[..]).clean(cx))
                     })
                     .collect::<Vec<_>>();
                 bounds.extend(regions);
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index 88d556229e4..5ab88260d6a 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -261,6 +261,7 @@
 
 use crate::cmp;
 use crate::fmt;
+use crate::mem;
 use crate::memchr;
 use crate::ops::{Deref, DerefMut};
 use crate::ptr;
@@ -1376,6 +1377,70 @@ pub trait Write {
         Ok(())
     }
 
+    /// Attempts to write multiple buffers into this writer.
+    ///
+    /// This method will continuously call [`write_vectored`] until there is no
+    /// more data to be written or an error of non-[`ErrorKind::Interrupted`]
+    /// kind is returned. This method will not return until all buffers have
+    /// been successfully written or such an error occurs. The first error that
+    /// is not of [`ErrorKind::Interrupted`] kind generated from this method
+    /// will be returned.
+    ///
+    /// If the buffer contains no data, this will never call [`write_vectored`].
+    ///
+    /// [`write_vectored`]: #method.write_vectored
+    /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
+    ///
+    /// # Notes
+    ///
+    ///
+    /// Unlike `io::Write::write_vectored`, this takes a *mutable* reference to
+    /// a slice of `IoSlice`s, not an immutable one. That's because we need to
+    /// modify the slice to keep track of the bytes already written.
+    ///
+    /// Once this function returns, the contents of `bufs` are unspecified, as
+    /// this depends on how many calls to `write_vectored` were necessary. It is
+    /// best to understand this function as taking ownership of `bufs` and to
+    /// not use `bufs` afterwards. The underlying buffers, to which the
+    /// `IoSlice`s point (but not the `IoSlice`s themselves), are unchanged and
+    /// can be reused.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(write_all_vectored)]
+    /// # fn main() -> std::io::Result<()> {
+    ///
+    /// use std::io::{Write, IoSlice};
+    ///
+    /// let mut writer = Vec::new();
+    /// let bufs = &mut [
+    ///     IoSlice::new(&[1]),
+    ///     IoSlice::new(&[2, 3]),
+    ///     IoSlice::new(&[4, 5, 6]),
+    /// ];
+    ///
+    /// writer.write_all_vectored(bufs)?;
+    /// // Note: the contents of `bufs` is now undefined, see the Notes section.
+    ///
+    /// assert_eq!(writer, &[1, 2, 3, 4, 5, 6]);
+    /// # Ok(()) }
+    /// ```
+    #[unstable(feature = "write_all_vectored", issue = "70436")]
+    fn write_all_vectored(&mut self, mut bufs: &mut [IoSlice<'_>]) -> Result<()> {
+        while !bufs.is_empty() {
+            match self.write_vectored(bufs) {
+                Ok(0) => {
+                    return Err(Error::new(ErrorKind::WriteZero, "failed to write whole buffer"));
+                }
+                Ok(n) => bufs = IoSlice::advance(mem::take(&mut bufs), n),
+                Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
+                Err(e) => return Err(e),
+            }
+        }
+        Ok(())
+    }
+
     /// Writes a formatted string into this writer, returning any error
     /// encountered.
     ///
@@ -2423,7 +2488,7 @@ impl<B: BufRead> Iterator for Lines<B> {
 #[cfg(test)]
 mod tests {
     use super::{repeat, Cursor, SeekFrom};
-    use crate::cmp;
+    use crate::cmp::{self, min};
     use crate::io::prelude::*;
     use crate::io::{self, IoSlice, IoSliceMut};
     use crate::ops::Deref;
@@ -2812,4 +2877,107 @@ mod tests {
         bufs = IoSlice::advance(bufs, 9);
         assert!(bufs.is_empty());
     }
+
+    /// Create a new writer that reads from at most `n_bufs` and reads
+    /// `per_call` bytes (in total) per call to write.
+    fn test_writer(n_bufs: usize, per_call: usize) -> TestWriter {
+        TestWriter { n_bufs, per_call, written: Vec::new() }
+    }
+
+    struct TestWriter {
+        n_bufs: usize,
+        per_call: usize,
+        written: Vec<u8>,
+    }
+
+    impl Write for TestWriter {
+        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+            self.write_vectored(&[IoSlice::new(buf)])
+        }
+
+        fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+            let mut left = self.per_call;
+            let mut written = 0;
+            for buf in bufs.iter().take(self.n_bufs) {
+                let n = min(left, buf.len());
+                self.written.extend_from_slice(&buf[0..n]);
+                left -= n;
+                written += n;
+            }
+            Ok(written)
+        }
+
+        fn flush(&mut self) -> io::Result<()> {
+            Ok(())
+        }
+    }
+
+    #[test]
+    fn test_writer_read_from_one_buf() {
+        let mut writer = test_writer(1, 2);
+
+        assert_eq!(writer.write(&[]).unwrap(), 0);
+        assert_eq!(writer.write_vectored(&[]).unwrap(), 0);
+
+        // Read at most 2 bytes.
+        assert_eq!(writer.write(&[1, 1, 1]).unwrap(), 2);
+        let bufs = &[IoSlice::new(&[2, 2, 2])];
+        assert_eq!(writer.write_vectored(bufs).unwrap(), 2);
+
+        // Only read from first buf.
+        let bufs = &[IoSlice::new(&[3]), IoSlice::new(&[4, 4])];
+        assert_eq!(writer.write_vectored(bufs).unwrap(), 1);
+
+        assert_eq!(writer.written, &[1, 1, 2, 2, 3]);
+    }
+
+    #[test]
+    fn test_writer_read_from_multiple_bufs() {
+        let mut writer = test_writer(3, 3);
+
+        // Read at most 3 bytes from two buffers.
+        let bufs = &[IoSlice::new(&[1]), IoSlice::new(&[2, 2, 2])];
+        assert_eq!(writer.write_vectored(bufs).unwrap(), 3);
+
+        // Read at most 3 bytes from three buffers.
+        let bufs = &[IoSlice::new(&[3]), IoSlice::new(&[4]), IoSlice::new(&[5, 5])];
+        assert_eq!(writer.write_vectored(bufs).unwrap(), 3);
+
+        assert_eq!(writer.written, &[1, 2, 2, 3, 4, 5]);
+    }
+
+    #[test]
+    fn test_write_all_vectored() {
+        #[rustfmt::skip] // Becomes unreadable otherwise.
+        let tests: Vec<(_, &'static [u8])> = vec![
+            (vec![], &[]),
+            (vec![IoSlice::new(&[1])], &[1]),
+            (vec![IoSlice::new(&[1, 2])], &[1, 2]),
+            (vec![IoSlice::new(&[1, 2, 3])], &[1, 2, 3]),
+            (vec![IoSlice::new(&[1, 2, 3, 4])], &[1, 2, 3, 4]),
+            (vec![IoSlice::new(&[1, 2, 3, 4, 5])], &[1, 2, 3, 4, 5]),
+            (vec![IoSlice::new(&[1]), IoSlice::new(&[2])], &[1, 2]),
+            (vec![IoSlice::new(&[1]), IoSlice::new(&[2, 2])], &[1, 2, 2]),
+            (vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2])], &[1, 1, 2, 2]),
+            (vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 2, 2, 2]),
+            (vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 2, 2, 2]),
+            (vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 1, 2, 2, 2]),
+            (vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2, 2])], &[1, 1, 1, 2, 2, 2, 2]),
+            (vec![IoSlice::new(&[1, 1, 1, 1]), IoSlice::new(&[2, 2, 2, 2])], &[1, 1, 1, 1, 2, 2, 2, 2]),
+            (vec![IoSlice::new(&[1]), IoSlice::new(&[2]), IoSlice::new(&[3])], &[1, 2, 3]),
+            (vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2]), IoSlice::new(&[3, 3])], &[1, 1, 2, 2, 3, 3]),
+            (vec![IoSlice::new(&[1]), IoSlice::new(&[2, 2]), IoSlice::new(&[3, 3, 3])], &[1, 2, 2, 3, 3, 3]),
+            (vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2]), IoSlice::new(&[3, 3, 3])], &[1, 1, 1, 2, 2, 2, 3, 3, 3]),
+        ];
+
+        let writer_configs = &[(1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)];
+
+        for (n_bufs, per_call) in writer_configs.iter().copied() {
+            for (mut input, wanted) in tests.clone().into_iter() {
+                let mut writer = test_writer(n_bufs, per_call);
+                assert!(writer.write_all_vectored(&mut *input).is_ok());
+                assert_eq!(&*writer.written, &*wanted);
+            }
+        }
+    }
 }
diff --git a/src/llvm-project b/src/llvm-project
-Subproject 130721d6f4e6cba3b910ccdf5e0aa62b9dffc95
+Subproject 027e428197f3702599cfbb632883768175f4917
diff --git a/src/test/ui/coherence/impl-foreign-for-locally-defined-fundamental.rs b/src/test/ui/coherence/impl-foreign-for-locally-defined-fundamental.rs
index 49b3abc99b7..bc1e18b657f 100644
--- a/src/test/ui/coherence/impl-foreign-for-locally-defined-fundamental.rs
+++ b/src/test/ui/coherence/impl-foreign-for-locally-defined-fundamental.rs
@@ -8,8 +8,8 @@ extern crate coherence_lib as lib;
 use lib::*;
 
 #[fundamental]
-struct Local;
+struct Local<T>(T);
 
-impl Remote for Local {}
+impl Remote for Local<()> {}
 
 fn main() {}
diff --git a/src/test/ui/consts/const-eval/issue-70723.rs b/src/test/ui/consts/const-eval/issue-70723.rs
new file mode 100644
index 00000000000..8b79d5d53c5
--- /dev/null
+++ b/src/test/ui/consts/const-eval/issue-70723.rs
@@ -0,0 +1,5 @@
+#![feature(const_loop)]
+
+static _X: () = loop {}; //~ ERROR could not evaluate static initializer
+
+fn main() {}
diff --git a/src/test/ui/consts/const-eval/issue-70723.stderr b/src/test/ui/consts/const-eval/issue-70723.stderr
new file mode 100644
index 00000000000..687d6565a71
--- /dev/null
+++ b/src/test/ui/consts/const-eval/issue-70723.stderr
@@ -0,0 +1,9 @@
+error[E0080]: could not evaluate static initializer
+  --> $DIR/issue-70723.rs:3:17
+   |
+LL | static _X: () = loop {};
+   |                 ^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/impl-trait/does-not-live-long-enough.stderr b/src/test/ui/impl-trait/does-not-live-long-enough.stderr
index 83d0f87015b..9cff4bcd8b5 100644
--- a/src/test/ui/impl-trait/does-not-live-long-enough.stderr
+++ b/src/test/ui/impl-trait/does-not-live-long-enough.stderr
@@ -14,7 +14,7 @@ LL |     }
 help: you can add a bound to the opaque type to make it last less than `'static` and match `'a`
    |
 LL |     fn started_with<'a>(&'a self, prefix: &'a str) -> impl Iterator<Item=&'a str> + 'a {
-   |                                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                                                                   ^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/layout/debug.rs b/src/test/ui/layout/debug.rs
index 034ed3190c1..299151df664 100644
--- a/src/test/ui/layout/debug.rs
+++ b/src/test/ui/layout/debug.rs
@@ -3,19 +3,19 @@
 #![crate_type = "lib"]
 
 #[rustc_layout(debug)]
-enum E { Foo, Bar(!, i32, i32) } //~ ERROR: layout debugging
+enum E { Foo, Bar(!, i32, i32) } //~ ERROR: layout_of
 
 #[rustc_layout(debug)]
-struct S { f1: i32, f2: (), f3: i32 } //~ ERROR: layout debugging
+struct S { f1: i32, f2: (), f3: i32 } //~ ERROR: layout_of
 
 #[rustc_layout(debug)]
-union U { f1: (i32, i32), f3: i32 } //~ ERROR: layout debugging
+union U { f1: (i32, i32), f3: i32 } //~ ERROR: layout_of
 
 #[rustc_layout(debug)]
-type Test = Result<i32, i32>; //~ ERROR: layout debugging
+type Test = Result<i32, i32>; //~ ERROR: layout_of
 
 #[rustc_layout(debug)]
-type T = impl std::fmt::Debug; //~ ERROR: layout debugging
+type T = impl std::fmt::Debug; //~ ERROR: layout_of
 
 fn f() -> T {
     0i32
diff --git a/src/test/ui/layout/debug.stderr b/src/test/ui/layout/debug.stderr
index 3539cea5ea3..153dec594d3 100644
--- a/src/test/ui/layout/debug.stderr
+++ b/src/test/ui/layout/debug.stderr
@@ -1,4 +1,4 @@
-error: layout debugging for type E: Layout {
+error: layout_of(E) = Layout {
     fields: Arbitrary {
         offsets: [
             Size {
@@ -110,7 +110,7 @@ error: layout debugging for type E: Layout {
 LL | enum E { Foo, Bar(!, i32, i32) }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: layout debugging for type S: Layout {
+error: layout_of(S) = Layout {
     fields: Arbitrary {
         offsets: [
             Size {
@@ -164,7 +164,7 @@ error: layout debugging for type S: Layout {
 LL | struct S { f1: i32, f2: (), f3: i32 }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: layout debugging for type U: Layout {
+error: layout_of(U) = Layout {
     fields: Union(
         2,
     ),
@@ -190,7 +190,7 @@ error: layout debugging for type U: Layout {
 LL | union U { f1: (i32, i32), f3: i32 }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: layout debugging for type std::result::Result<i32, i32>: Layout {
+error: layout_of(std::result::Result<i32, i32>) = Layout {
     fields: Arbitrary {
         offsets: [
             Size {
@@ -315,7 +315,7 @@ error: layout debugging for type std::result::Result<i32, i32>: Layout {
 LL | type Test = Result<i32, i32>;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: layout debugging for type i32: Layout {
+error: layout_of(i32) = Layout {
     fields: Union(
         0,
     ),
diff --git a/src/test/ui/parser/issue-32214.stderr b/src/test/ui/parser/issue-32214.stderr
index 742f4fdc38b..bc61b3b74e2 100644
--- a/src/test/ui/parser/issue-32214.stderr
+++ b/src/test/ui/parser/issue-32214.stderr
@@ -4,7 +4,12 @@ error: generic arguments must come before the first constraint
 LL | pub fn test<W, I: Trait<Item=(), W> >() {}
    |                         -------  ^ generic argument
    |                         |
-   |                         the first constraint is provided here
+   |                         constraint
+   |
+help: move the constraint after the generic argument
+   |
+LL | pub fn test<W, I: Trait<W, Item = ()> >() {}
+   |                        ^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs b/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs
new file mode 100644
index 00000000000..cc36f054bc3
--- /dev/null
+++ b/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs
@@ -0,0 +1,20 @@
+// edition:2018
+
+async fn free(); //~ ERROR without a body
+
+struct A;
+impl A {
+    async fn inherent(); //~ ERROR without body
+}
+
+trait B {
+    async fn associated();
+    //~^ ERROR cannot be declared `async`
+}
+impl B for A {
+    async fn associated(); //~ ERROR without body
+    //~^ ERROR cannot be declared `async`
+    //~| ERROR incompatible type for trait
+}
+
+fn main() {}
diff --git a/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr b/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr
new file mode 100644
index 00000000000..a324d04d394
--- /dev/null
+++ b/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr
@@ -0,0 +1,65 @@
+error: free function without a body
+  --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:3:1
+   |
+LL | async fn free();
+   | ^^^^^^^^^^^^^^^-
+   |                |
+   |                help: provide a definition for the function: `{ <body> }`
+
+error: associated function in `impl` without body
+  --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:7:5
+   |
+LL |     async fn inherent();
+   |     ^^^^^^^^^^^^^^^^^^^-
+   |                        |
+   |                        help: provide a definition for the function: `{ <body> }`
+
+error[E0706]: functions in traits cannot be declared `async`
+  --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:11:5
+   |
+LL |     async fn associated();
+   |     -----^^^^^^^^^^^^^^^^^
+   |     |
+   |     `async` because of this
+   |
+   = note: `async` trait functions are not currently supported
+   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+
+error: associated function in `impl` without body
+  --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:15:5
+   |
+LL |     async fn associated();
+   |     ^^^^^^^^^^^^^^^^^^^^^-
+   |                          |
+   |                          help: provide a definition for the function: `{ <body> }`
+
+error[E0706]: functions in traits cannot be declared `async`
+  --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:15:5
+   |
+LL |     async fn associated();
+   |     -----^^^^^^^^^^^^^^^^^
+   |     |
+   |     `async` because of this
+   |
+   = note: `async` trait functions are not currently supported
+   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+
+error[E0053]: method `associated` has an incompatible type for trait
+  --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:15:26
+   |
+LL |     async fn associated();
+   |                          - type in trait
+...
+LL |     async fn associated();
+   |                          ^
+   |                          |
+   |                          the `Output` of this `async fn`'s found opaque type
+   |                          expected `()`, found opaque type
+   |
+   = note: expected fn pointer `fn()`
+              found fn pointer `fn() -> impl std::future::Future`
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0053, E0706.
+For more information about an error, try `rustc --explain E0053`.
diff --git a/src/test/ui/sanitize-inline-always.rs b/src/test/ui/sanitize/inline-always.rs
index 52dc5578180..52dc5578180 100644
--- a/src/test/ui/sanitize-inline-always.rs
+++ b/src/test/ui/sanitize/inline-always.rs
diff --git a/src/test/ui/sanitize-inline-always.stderr b/src/test/ui/sanitize/inline-always.stderr
index 50b9474baa2..84c05af4cf8 100644
--- a/src/test/ui/sanitize-inline-always.stderr
+++ b/src/test/ui/sanitize/inline-always.stderr
@@ -1,12 +1,12 @@
 warning: `no_sanitize` will have no effect after inlining
-  --> $DIR/sanitize-inline-always.rs:7:1
+  --> $DIR/inline-always.rs:7:1
    |
 LL | #[no_sanitize(address)]
    | ^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `#[warn(inline_no_sanitize)]` on by default
 note: inlining requested here
-  --> $DIR/sanitize-inline-always.rs:5:1
+  --> $DIR/inline-always.rs:5:1
    |
 LL | #[inline(always)]
    | ^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/suggestions/suggest-move-types.stderr b/src/test/ui/suggestions/suggest-move-types.stderr
index 4dd0613757a..3bb6fd6e4f4 100644
--- a/src/test/ui/suggestions/suggest-move-types.stderr
+++ b/src/test/ui/suggestions/suggest-move-types.stderr
@@ -4,79 +4,103 @@ error: generic arguments must come before the first constraint
 LL | struct A<T, M: One<A=(), T>> {
    |                    ----  ^ generic argument
    |                    |
-   |                    the first constraint is provided here
+   |                    constraint
+   |
+help: move the constraint after the generic argument
+   |
+LL | struct A<T, M: One<T, A = ()>> {
+   |                   ^^^^^^^^^^^
 
 error: generic arguments must come before the first constraint
   --> $DIR/suggest-move-types.rs:33:43
    |
 LL | struct Al<'a, T, M: OneWithLifetime<A=(), T, 'a>> {
-   |                                     ----  ^  ^^ generic argument
-   |                                     |     |
-   |                                     |     generic argument
-   |                                     the first constraint is provided here
+   |                                     ----  ^  ^^ generic arguments
+   |                                     |
+   |                                     constraint
+   |
+help: move the constraint after the generic arguments
+   |
+LL | struct Al<'a, T, M: OneWithLifetime<'a, T, A = ()>> {
+   |                                    ^^^^^^^^^^^^^^^
 
 error: generic arguments must come before the first constraint
   --> $DIR/suggest-move-types.rs:40:46
    |
 LL | struct B<T, U, V, M: Three<A=(), B=(), C=(), T, U, V>> {
-   |                            ----              ^  ^  ^ generic argument
-   |                            |                 |  |
-   |                            |                 |  generic argument
-   |                            |                 generic argument
-   |                            the first constraint is provided here
+   |                            ----  ----  ----  ^  ^  ^ generic arguments
+   |                            |
+   |                            constraints
+   |
+help: move the constraints after the generic arguments
+   |
+LL | struct B<T, U, V, M: Three<T, U, V, A = (), B = (), C = ()>> {
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: generic arguments must come before the first constraint
   --> $DIR/suggest-move-types.rs:48:71
    |
 LL | struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<A=(), B=(), C=(), T, U, V, 'a, 'b, 'c>> {
-   |                                                     ----              ^  ^  ^  ^^  ^^  ^^ generic argument
-   |                                                     |                 |  |  |  |   |
-   |                                                     |                 |  |  |  |   generic argument
-   |                                                     |                 |  |  |  generic argument
-   |                                                     |                 |  |  generic argument
-   |                                                     |                 |  generic argument
-   |                                                     |                 generic argument
-   |                                                     the first constraint is provided here
+   |                                                     ----  ----  ----  ^  ^  ^  ^^  ^^  ^^ generic arguments
+   |                                                     |
+   |                                                     constraints
+   |
+help: move the constraints after the generic arguments
+   |
+LL | struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<'a, 'b, 'c, T, U, V, A = (), B = (), C = ()>> {
+   |                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: generic arguments must come before the first constraint
-  --> $DIR/suggest-move-types.rs:57:49
+  --> $DIR/suggest-move-types.rs:57:28
    |
 LL | struct C<T, U, V, M: Three<T, A=(), B=(), C=(), U, V>> {
-   |                               ----              ^  ^ generic argument
-   |                               |                 |
-   |                               |                 generic argument
-   |                               the first constraint is provided here
+   |                            ^  ----  ----  ----  ^  ^ generic arguments
+   |                               |
+   |                               constraints
+   |
+help: move the constraints after the generic arguments
+   |
+LL | struct C<T, U, V, M: Three<T, U, V, A = (), B = (), C = ()>> {
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: generic arguments must come before the first constraint
-  --> $DIR/suggest-move-types.rs:65:78
+  --> $DIR/suggest-move-types.rs:65:53
    |
 LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), C=(), U, 'b, V, 'c>> {
-   |                                                            ----              ^  ^^  ^  ^^ generic argument
-   |                                                            |                 |  |   |
-   |                                                            |                 |  |   generic argument
-   |                                                            |                 |  generic argument
-   |                                                            |                 generic argument
-   |                                                            the first constraint is provided here
+   |                                                     ^  ^^  ----  ----  ----  ^  ^^  ^  ^^ generic arguments
+   |                                                            |
+   |                                                            constraints
+   |
+help: move the constraints after the generic arguments
+   |
+LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<'a, 'b, 'c, T, U, V, A = (), B = (), C = ()>> {
+   |                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: generic arguments must come before the first constraint
-  --> $DIR/suggest-move-types.rs:74:43
+  --> $DIR/suggest-move-types.rs:74:28
    |
 LL | struct D<T, U, V, M: Three<T, A=(), B=(), U, C=(), V>> {
-   |                               ----        ^        ^ generic argument
-   |                               |           |
-   |                               |           generic argument
-   |                               the first constraint is provided here
+   |                            ^  ----  ----  ^  ----  ^ generic arguments
+   |                               |
+   |                               constraints
+   |
+help: move the constraints after the generic arguments
+   |
+LL | struct D<T, U, V, M: Three<T, U, V, A = (), B = (), C = ()>> {
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: generic arguments must come before the first constraint
-  --> $DIR/suggest-move-types.rs:82:72
+  --> $DIR/suggest-move-types.rs:82:53
    |
 LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), U, 'b, C=(), V, 'c>> {
-   |                                                            ----        ^  ^^        ^  ^^ generic argument
-   |                                                            |           |  |         |
-   |                                                            |           |  |         generic argument
-   |                                                            |           |  generic argument
-   |                                                            |           generic argument
-   |                                                            the first constraint is provided here
+   |                                                     ^  ^^  ----  ----  ^  ^^  ----  ^  ^^ generic arguments
+   |                                                            |
+   |                                                            constraints
+   |
+help: move the constraints after the generic arguments
+   |
+LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<'a, 'b, 'c, T, U, V, A = (), B = (), C = ()>> {
+   |                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0747]: type provided when a lifetime was expected
   --> $DIR/suggest-move-types.rs:33:43