diff --git a/README.md b/README.md
index 42fc0a63c0ffb..c2ded10f05a36 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,9 @@
-# The Rust Programming Language
+<a href = "https://www.rust-lang.org/"> 
+<img width = "90%" height = "auto" src = "https://img.shields.io/badge/Rust-Programming%20Language-black?style=flat&logo=rust" alt = "The Rust Programming Language">
+</a>
 
 This is the main source code repository for [Rust]. It contains the compiler,
-standard library, and documentation.
+standard library, and documentation. 
 
 [Rust]: https://www.rust-lang.org
 
@@ -17,9 +19,9 @@ Read ["Installation"] from [The Book].
 _Note: If you wish to contribute to the compiler, you should read [this
 chapter][rustcguidebuild] of the rustc-dev-guide instead of this section._
 
-The Rust build system has a Python script called `x.py` to bootstrap building
-the compiler. More information about it may be found by running `./x.py --help`
-or reading the [rustc dev guide][rustcguidebuild].
+The Rust build system uses a Python script called `x.py` to build the compiler,
+which manages the bootstrapping process. More information about it can be found 
+by running `./x.py --help` or reading the [rustc dev guide][rustcguidebuild].
 
 [rustcguidebuild]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html
 
@@ -54,9 +56,8 @@ or reading the [rustc dev guide][rustcguidebuild].
     $ cp config.toml.example config.toml
     ```
 
-    It is recommended that if you plan to use the Rust build system to create
-    an installation (using `./x.py install`) that you set the `prefix` value
-    in the `[install]` section to a directory that you have write permissions.
+    If you plan to use `x.py install` to create an installation, it is recommended
+    that you set the `prefix` value in the `[install]` section to a directory.
 
     Create install directory if you are not installing in default directory
 
@@ -143,8 +144,8 @@ shell with:
 ```
 
 Currently, building Rust only works with some known versions of Visual Studio. If
-you have a more recent version installed the build system doesn't understand
-then you may need to force rustbuild to use an older version. This can be done
+you have a more recent version installed and the build system doesn't understand,
+you may need to force rustbuild to use an older version. This can be done
 by manually calling the appropriate vcvars file before running the bootstrap.
 
 ```batch
diff --git a/src/doc/unstable-book/src/language-features/track-caller.md b/src/doc/unstable-book/src/language-features/track-caller.md
deleted file mode 100644
index afc11a2b9492c..0000000000000
--- a/src/doc/unstable-book/src/language-features/track-caller.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# `track_caller`
-
-The tracking issue for this feature is: [#47809](https://github.com/rust-lang/rust/issues/47809).
-
-------------------------
diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs
index f1b560b9b9685..3320ebdf821d0 100644
--- a/src/liballoc/boxed.rs
+++ b/src/liballoc/boxed.rs
@@ -384,7 +384,10 @@ impl<T: ?Sized> Box<T> {
     ///
     /// unsafe {
     ///     let ptr = alloc(Layout::new::<i32>()) as *mut i32;
-    ///     *ptr = 5;
+    ///     // In general .write is required to avoid attempting to destruct
+    ///     // the (uninitialized) previous contents of `ptr`, though for this
+    ///     // simple example `*ptr = 5` would have worked as well.
+    ///     ptr.write(5);
     ///     let x = Box::from_raw(ptr);
     /// }
     /// ```
diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs
index 64d9692244dde..13ef94dee2326 100644
--- a/src/liballoc/string.rs
+++ b/src/liballoc/string.rs
@@ -2518,3 +2518,11 @@ impl DoubleEndedIterator for Drain<'_> {
 
 #[stable(feature = "fused", since = "1.26.0")]
 impl FusedIterator for Drain<'_> {}
+
+#[stable(feature = "from_char_for_string", since = "1.46.0")]
+impl From<char> for String {
+    #[inline]
+    fn from(c: char) -> Self {
+        c.to_string()
+    }
+}
diff --git a/src/liballoc/tests/string.rs b/src/liballoc/tests/string.rs
index 9ea020d2d19f4..d38655af78cb7 100644
--- a/src/liballoc/tests/string.rs
+++ b/src/liballoc/tests/string.rs
@@ -714,3 +714,10 @@ fn test_try_reserve_exact() {
         }
     }
 }
+
+#[test]
+fn test_from_char() {
+    assert_eq!(String::from('a'), 'a'.to_string());
+    let s: String = 'x'.into();
+    assert_eq!(s, 'x'.to_string());
+}
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index 5d09018759191..57ffed19c0085 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -952,6 +952,7 @@ extern "rust-intrinsic" {
     /// Any use other than with `if` statements will probably not have an effect.
     ///
     /// This intrinsic does not have a stable counterpart.
+    #[rustc_const_unstable(feature = "const_likely", issue = "none")]
     pub fn likely(b: bool) -> bool;
 
     /// Hints to the compiler that branch condition is likely to be false.
@@ -960,6 +961,7 @@ extern "rust-intrinsic" {
     /// Any use other than with `if` statements will probably not have an effect.
     ///
     /// This intrinsic does not have a stable counterpart.
+    #[rustc_const_unstable(feature = "const_likely", issue = "none")]
     pub fn unlikely(b: bool) -> bool;
 
     /// Executes a breakpoint trap, for inspection by a debugger.
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index aeb52bffbf24c..63ddd97eed3df 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -92,6 +92,7 @@
 #![feature(const_slice_from_raw_parts)]
 #![feature(const_slice_ptr_len)]
 #![feature(const_type_name)]
+#![feature(const_likely)]
 #![feature(custom_inner_attributes)]
 #![feature(decl_macro)]
 #![feature(doc_cfg)]
@@ -118,7 +119,7 @@
 #![feature(staged_api)]
 #![feature(std_internals)]
 #![feature(stmt_expr_attributes)]
-#![feature(track_caller)]
+#![cfg_attr(bootstrap, feature(track_caller))]
 #![feature(transparent_unions)]
 #![feature(unboxed_closures)]
 #![feature(unsized_locals)]
diff --git a/src/libcore/macros/mod.rs b/src/libcore/macros/mod.rs
index 3cfdde60135b7..13c0e8daf740f 100644
--- a/src/libcore/macros/mod.rs
+++ b/src/libcore/macros/mod.rs
@@ -1,6 +1,6 @@
 #[doc(include = "panic.md")]
 #[macro_export]
-#[allow_internal_unstable(core_panic, track_caller)]
+#[allow_internal_unstable(core_panic, const_caller_location)]
 #[stable(feature = "core", since = "1.6.0")]
 macro_rules! panic {
     () => (
diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs
index c7009b76e8148..543aa969330ae 100644
--- a/src/libcore/panic.rs
+++ b/src/libcore/panic.rs
@@ -190,7 +190,6 @@ impl<'a> Location<'a> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(track_caller)]
     /// use core::panic::Location;
     ///
     /// /// Returns the [`Location`] at which it is called.
@@ -206,7 +205,7 @@ impl<'a> Location<'a> {
     ///
     /// let fixed_location = get_just_one_location();
     /// assert_eq!(fixed_location.file(), file!());
-    /// assert_eq!(fixed_location.line(), 15);
+    /// assert_eq!(fixed_location.line(), 14);
     /// assert_eq!(fixed_location.column(), 5);
     ///
     /// // running the same untracked function in a different location gives us the same result
@@ -217,7 +216,7 @@ impl<'a> Location<'a> {
     ///
     /// let this_location = get_caller_location();
     /// assert_eq!(this_location.file(), file!());
-    /// assert_eq!(this_location.line(), 29);
+    /// assert_eq!(this_location.line(), 28);
     /// assert_eq!(this_location.column(), 21);
     ///
     /// // running the tracked function in a different location produces a different value
@@ -226,13 +225,8 @@ impl<'a> Location<'a> {
     /// assert_ne!(this_location.line(), another_location.line());
     /// assert_ne!(this_location.column(), another_location.column());
     /// ```
-    // FIXME: When stabilizing this method, please also update the documentation
-    // of `intrinsics::caller_location`.
-    #[unstable(
-        feature = "track_caller",
-        reason = "uses #[track_caller] which is not yet stable",
-        issue = "47809"
-    )]
+    #[stable(feature = "track_caller", since = "1.46.0")]
+    #[rustc_const_unstable(feature = "const_caller_location", issue = "47809")]
     #[track_caller]
     pub const fn caller() -> &'static Location<'static> {
         crate::intrinsics::caller_location()
diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs
index 86faa1f086ce2..501cd3748282b 100644
--- a/src/librustc_ast_pretty/pprust.rs
+++ b/src/librustc_ast_pretty/pprust.rs
@@ -9,7 +9,7 @@ use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_ast::attr;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, BinOpToken, DelimToken, Nonterminal, Token, TokenKind};
-use rustc_ast::tokenstream::{self, TokenStream, TokenTree};
+use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_ast::util::parser::{self, AssocOp, Fixity};
 use rustc_ast::util::{classify, comments};
 use rustc_span::edition::Edition;
@@ -293,7 +293,7 @@ pub fn nonterminal_to_string(nt: &Nonterminal) -> String {
         token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(e, is_raw).to_string(),
         token::NtLifetime(e) => e.to_string(),
         token::NtLiteral(ref e) => expr_to_string(e),
-        token::NtTT(ref tree) => tt_to_string(tree.clone()),
+        token::NtTT(ref tree) => tt_to_string(tree),
         token::NtVis(ref e) => vis_to_string(e),
     }
 }
@@ -314,11 +314,11 @@ pub fn expr_to_string(e: &ast::Expr) -> String {
     to_string(|s| s.print_expr(e))
 }
 
-pub fn tt_to_string(tt: tokenstream::TokenTree) -> String {
+pub fn tt_to_string(tt: &TokenTree) -> String {
     to_string(|s| s.print_tt(tt, false))
 }
 
-pub fn tts_to_string(tokens: TokenStream) -> String {
+pub fn tts_to_string(tokens: &TokenStream) -> String {
     to_string(|s| s.print_tts(tokens, false))
 }
 
@@ -585,7 +585,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
                 false,
                 None,
                 delim.to_token(),
-                tokens.clone(),
+                tokens,
                 true,
                 span,
             ),
@@ -594,7 +594,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
                 if let MacArgs::Eq(_, tokens) = &item.args {
                     self.space();
                     self.word_space("=");
-                    self.print_tts(tokens.clone(), true);
+                    self.print_tts(tokens, true);
                 }
             }
         }
@@ -635,9 +635,9 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
     /// appropriate macro, transcribe back into the grammar we just parsed from,
     /// and then pretty-print the resulting AST nodes (so, e.g., we print
     /// expression arguments as expressions). It can be done! I think.
-    fn print_tt(&mut self, tt: tokenstream::TokenTree, convert_dollar_crate: bool) {
+    fn print_tt(&mut self, tt: &TokenTree, convert_dollar_crate: bool) {
         match tt {
-            TokenTree::Token(ref token) => {
+            TokenTree::Token(token) => {
                 self.word(token_to_string_ext(&token, convert_dollar_crate));
                 if let token::DocComment(..) = token.kind {
                     self.hardbreak()
@@ -648,7 +648,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
                     None,
                     false,
                     None,
-                    delim,
+                    *delim,
                     tts,
                     convert_dollar_crate,
                     dspan.entire(),
@@ -657,14 +657,14 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
         }
     }
 
-    fn print_tts(&mut self, tts: tokenstream::TokenStream, convert_dollar_crate: bool) {
-        let mut iter = tts.into_trees().peekable();
+    fn print_tts(&mut self, tts: &TokenStream, convert_dollar_crate: bool) {
+        let mut iter = tts.trees().peekable();
         while let Some(tt) = iter.next() {
-            let show_space =
-                if let Some(next) = iter.peek() { tt_prepend_space(next, &tt) } else { false };
-            self.print_tt(tt, convert_dollar_crate);
-            if show_space {
-                self.space();
+            self.print_tt(&tt, convert_dollar_crate);
+            if let Some(next) = iter.peek() {
+                if tt_prepend_space(next, &tt) {
+                    self.space();
+                }
             }
         }
     }
@@ -675,7 +675,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
         has_bang: bool,
         ident: Option<Ident>,
         delim: DelimToken,
-        tts: TokenStream,
+        tts: &TokenStream,
         convert_dollar_crate: bool,
         span: Span,
     ) {
@@ -1253,7 +1253,7 @@ impl<'a> State<'a> {
                     has_bang,
                     Some(item.ident),
                     macro_def.body.delim(),
-                    macro_def.body.inner_tokens(),
+                    &macro_def.body.inner_tokens(),
                     true,
                     item.span,
                 );
@@ -1577,7 +1577,7 @@ impl<'a> State<'a> {
             true,
             None,
             m.args.delim(),
-            m.args.inner_tokens(),
+            &m.args.inner_tokens(),
             true,
             m.span(),
         );
diff --git a/src/librustc_builtin_macros/log_syntax.rs b/src/librustc_builtin_macros/log_syntax.rs
index ae3a889428ae4..ede34a7612589 100644
--- a/src/librustc_builtin_macros/log_syntax.rs
+++ b/src/librustc_builtin_macros/log_syntax.rs
@@ -7,7 +7,7 @@ pub fn expand_log_syntax<'cx>(
     sp: rustc_span::Span,
     tts: TokenStream,
 ) -> Box<dyn base::MacResult + 'cx> {
-    println!("{}", pprust::tts_to_string(tts));
+    println!("{}", pprust::tts_to_string(&tts));
 
     // any so that `log_syntax` can be invoked as an expression and item.
     base::DummyResult::any_valid(sp)
diff --git a/src/librustc_builtin_macros/source_util.rs b/src/librustc_builtin_macros/source_util.rs
index 1b164eae5a345..e46cf67e64d66 100644
--- a/src/librustc_builtin_macros/source_util.rs
+++ b/src/librustc_builtin_macros/source_util.rs
@@ -71,7 +71,7 @@ pub fn expand_stringify(
     tts: TokenStream,
 ) -> Box<dyn base::MacResult + 'static> {
     let sp = cx.with_def_site_ctxt(sp);
-    let s = pprust::tts_to_string(tts);
+    let s = pprust::tts_to_string(&tts);
     base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&s)))
 }
 
diff --git a/src/librustc_error_codes/error_codes/E0736.md b/src/librustc_error_codes/error_codes/E0736.md
index 8a60dc320599b..0f3d41ba66dc4 100644
--- a/src/librustc_error_codes/error_codes/E0736.md
+++ b/src/librustc_error_codes/error_codes/E0736.md
@@ -3,8 +3,6 @@
 Erroneous code example:
 
 ```compile_fail,E0736
-#![feature(track_caller)]
-
 #[naked]
 #[track_caller]
 fn foo() {}
diff --git a/src/librustc_error_codes/error_codes/E0737.md b/src/librustc_error_codes/error_codes/E0737.md
index c6553e97b7e91..ab5e60692b4da 100644
--- a/src/librustc_error_codes/error_codes/E0737.md
+++ b/src/librustc_error_codes/error_codes/E0737.md
@@ -5,8 +5,6 @@ restrictions.
 Erroneous code example:
 
 ```compile_fail,E0737
-#![feature(track_caller)]
-
 #[track_caller]
 extern "C" fn foo() {}
 ```
diff --git a/src/librustc_error_codes/error_codes/E0739.md b/src/librustc_error_codes/error_codes/E0739.md
index 707751066edbc..8d9039bef93f6 100644
--- a/src/librustc_error_codes/error_codes/E0739.md
+++ b/src/librustc_error_codes/error_codes/E0739.md
@@ -3,7 +3,6 @@
 Erroneous code example:
 
 ```compile_fail,E0739
-#![feature(track_caller)]
 #[track_caller]
 struct Bar {
     a: u8,
diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs
index 0c1418d3cad27..362913ceadf18 100644
--- a/src/librustc_errors/lib.rs
+++ b/src/librustc_errors/lib.rs
@@ -5,7 +5,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![feature(crate_visibility_modifier)]
 #![feature(nll)]
-#![feature(track_caller)]
+#![cfg_attr(bootstrap, feature(track_caller))]
 
 pub use emitter::ColorConfig;
 
diff --git a/src/librustc_expand/mbe/macro_rules.rs b/src/librustc_expand/mbe/macro_rules.rs
index 8cdb5b09c9e8b..28a3970918ee6 100644
--- a/src/librustc_expand/mbe/macro_rules.rs
+++ b/src/librustc_expand/mbe/macro_rules.rs
@@ -224,7 +224,7 @@ fn generic_extension<'cx>(
     let sess = cx.parse_sess;
 
     if cx.trace_macros() {
-        let msg = format!("expanding `{}! {{ {} }}`", name, pprust::tts_to_string(arg.clone()));
+        let msg = format!("expanding `{}! {{ {} }}`", name, pprust::tts_to_string(&arg));
         trace_macros_note(&mut cx.expansions, sp, msg);
     }
 
@@ -300,7 +300,7 @@ fn generic_extension<'cx>(
                 }
 
                 if cx.trace_macros() {
-                    let msg = format!("to `{}`", pprust::tts_to_string(tts.clone()));
+                    let msg = format!("to `{}`", pprust::tts_to_string(&tts));
                     trace_macros_note(&mut cx.expansions, sp, msg);
                 }
 
diff --git a/src/librustc_expand/proc_macro_server.rs b/src/librustc_expand/proc_macro_server.rs
index c88b5a37f718a..e5e530227e43a 100644
--- a/src/librustc_expand/proc_macro_server.rs
+++ b/src/librustc_expand/proc_macro_server.rs
@@ -413,7 +413,7 @@ impl server::TokenStream for Rustc<'_> {
         )
     }
     fn to_string(&mut self, stream: &Self::TokenStream) -> String {
-        pprust::tts_to_string(stream.clone())
+        pprust::tts_to_string(stream)
     }
     fn from_token_tree(
         &mut self,
diff --git a/src/librustc_feature/accepted.rs b/src/librustc_feature/accepted.rs
index b164b21913d6e..d93c17b05b498 100644
--- a/src/librustc_feature/accepted.rs
+++ b/src/librustc_feature/accepted.rs
@@ -265,6 +265,9 @@ declare_features! (
     (accepted, const_if_match, "1.45.0", Some(49146), None),
     /// Allows the use of `loop` and `while` in constants.
     (accepted, const_loop, "1.45.0", Some(52000), None),
+    /// Allows `#[track_caller]` to be used which provides
+    /// accurate caller location reporting during panic (RFC 2091).
+    (accepted, track_caller, "1.46.0", Some(47809), None),
 
     // -------------------------------------------------------------------------
     // feature-group-end: accepted features
diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs
index 8660d6a8d6410..b9a55377949f2 100644
--- a/src/librustc_feature/active.rs
+++ b/src/librustc_feature/active.rs
@@ -494,10 +494,6 @@ declare_features! (
     /// Allows the use of raw-dylibs (RFC 2627).
     (active, raw_dylib, "1.40.0", Some(58713), None),
 
-    /// Allows `#[track_caller]` to be used which provides
-    /// accurate caller location reporting during panic (RFC 2091).
-    (active, track_caller, "1.40.0", Some(47809), None),
-
     /// Allows making `dyn Trait` well-formed even if `Trait` is not object safe.
     /// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and
     /// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden.
diff --git a/src/librustc_feature/builtin_attrs.rs b/src/librustc_feature/builtin_attrs.rs
index 524a357971029..c9a34f033758b 100644
--- a/src/librustc_feature/builtin_attrs.rs
+++ b/src/librustc_feature/builtin_attrs.rs
@@ -260,6 +260,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ungated!(cold, Whitelisted, template!(Word)),
     ungated!(no_builtins, Whitelisted, template!(Word)),
     ungated!(target_feature, Whitelisted, template!(List: r#"enable = "name""#)),
+    ungated!(track_caller, Whitelisted, template!(Word)),
     gated!(
         no_sanitize, Whitelisted,
         template!(List: "address, memory, thread"),
@@ -333,7 +334,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     gated!(ffi_returns_twice, Whitelisted, template!(Word), experimental!(ffi_returns_twice)),
     gated!(ffi_pure, Whitelisted, template!(Word), experimental!(ffi_pure)),
     gated!(ffi_const, Whitelisted, template!(Word), experimental!(ffi_const)),
-    gated!(track_caller, Whitelisted, template!(Word), experimental!(track_caller)),
     gated!(
         register_attr, CrateLevel, template!(List: "attr1, attr2, ..."),
         experimental!(register_attr),
diff --git a/src/librustc_infer/infer/at.rs b/src/librustc_infer/infer/at.rs
index d44b8f554143c..a7749d33b7c13 100644
--- a/src/librustc_infer/infer/at.rs
+++ b/src/librustc_infer/infer/at.rs
@@ -82,7 +82,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     where
         T: ToTrace<'tcx>,
     {
-        self.trace_exp(a_is_expected, a, b).sub(&a, &b)
+        self.trace_exp(a_is_expected, a, b).sub(a, b)
     }
 
     /// Makes `actual <: expected`. For example, if type-checking a
@@ -109,7 +109,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     where
         T: ToTrace<'tcx>,
     {
-        self.trace_exp(a_is_expected, a, b).eq(&a, &b)
+        self.trace_exp(a_is_expected, a, b).eq(a, b)
     }
 
     /// Makes `expected <: actual`.
@@ -117,7 +117,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     where
         T: ToTrace<'tcx>,
     {
-        self.trace(expected, actual).eq(&expected, &actual)
+        self.trace(expected, actual).eq(expected, actual)
     }
 
     pub fn relate<T>(self, expected: T, variance: ty::Variance, actual: T) -> InferResult<'tcx, ()>
@@ -147,7 +147,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     where
         T: ToTrace<'tcx>,
     {
-        self.trace(expected, actual).lub(&expected, &actual)
+        self.trace(expected, actual).lub(expected, actual)
     }
 
     /// Computes the greatest-lower-bound, or mutual subtype, of two
@@ -157,7 +157,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     where
         T: ToTrace<'tcx>,
     {
-        self.trace(expected, actual).glb(&expected, &actual)
+        self.trace(expected, actual).glb(expected, actual)
     }
 
     /// Sets the "trace" values that will be used for
@@ -186,7 +186,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
 impl<'a, 'tcx> Trace<'a, 'tcx> {
     /// Makes `a <: b` where `a` may or may not be expected (if
     /// `a_is_expected` is true, then `a` is expected).
-    pub fn sub<T>(self, a: &T, b: &T) -> InferResult<'tcx, ()>
+    pub fn sub<T>(self, a: T, b: T) -> InferResult<'tcx, ()>
     where
         T: Relate<'tcx>,
     {
@@ -203,7 +203,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
 
     /// Makes `a == b`; the expectation is set by the call to
     /// `trace()`.
-    pub fn eq<T>(self, a: &T, b: &T) -> InferResult<'tcx, ()>
+    pub fn eq<T>(self, a: T, b: T) -> InferResult<'tcx, ()>
     where
         T: Relate<'tcx>,
     {
@@ -218,7 +218,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
         })
     }
 
-    pub fn lub<T>(self, a: &T, b: &T) -> InferResult<'tcx, T>
+    pub fn lub<T>(self, a: T, b: T) -> InferResult<'tcx, T>
     where
         T: Relate<'tcx>,
     {
@@ -233,7 +233,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
         })
     }
 
-    pub fn glb<T>(self, a: &T, b: &T) -> InferResult<'tcx, T>
+    pub fn glb<T>(self, a: T, b: T) -> InferResult<'tcx, T>
     where
         T: Relate<'tcx>,
     {
diff --git a/src/librustc_infer/infer/canonical/query_response.rs b/src/librustc_infer/infer/canonical/query_response.rs
index 8af526e3ad31b..5cba581b9dffb 100644
--- a/src/librustc_infer/infer/canonical/query_response.rs
+++ b/src/librustc_infer/infer/canonical/query_response.rs
@@ -271,7 +271,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
                         },
                         ty::Variance::Invariant,
                     )
-                    .relate(&v1, &v2)?;
+                    .relate(v1, v2)?;
                 }
 
                 (GenericArgKind::Const(v1), GenericArgKind::Const(v2)) => {
@@ -285,7 +285,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
                         },
                         ty::Variance::Invariant,
                     )
-                    .relate(&v1, &v2)?;
+                    .relate(v1, v2)?;
                 }
 
                 _ => {
@@ -302,7 +302,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
                 // Screen out `'a: 'a` cases -- we skip the binder here but
                 // only compare the inner values to one another, so they are still at
                 // consistent binding levels.
-                let &ty::OutlivesPredicate(k1, r2) = r_c.skip_binder();
+                let ty::OutlivesPredicate(k1, r2) = r_c.skip_binder();
                 if k1 != r2.into() { Some(r_c) } else { None }
             }),
         );
@@ -526,7 +526,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
     ) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'a + Captures<'tcx> {
         unsubstituted_region_constraints.iter().map(move |constraint| {
             let constraint = substitute_value(self.tcx, result_subst, constraint);
-            let &ty::OutlivesPredicate(k1, r2) = constraint.skip_binder(); // restored below
+            let ty::OutlivesPredicate(k1, r2) = constraint.skip_binder(); // restored below
 
             Obligation::new(
                 cause.clone(),
diff --git a/src/librustc_infer/infer/combine.rs b/src/librustc_infer/infer/combine.rs
index 4ef4ed47cb11a..c8d4e9f0e14b9 100644
--- a/src/librustc_infer/infer/combine.rs
+++ b/src/librustc_infer/infer/combine.rs
@@ -318,10 +318,10 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
         // to associate causes/spans with each of the relations in
         // the stack to get this right.
         match dir {
-            EqTo => self.equate(a_is_expected).relate(&a_ty, &b_ty),
-            SubtypeOf => self.sub(a_is_expected).relate(&a_ty, &b_ty),
+            EqTo => self.equate(a_is_expected).relate(a_ty, b_ty),
+            SubtypeOf => self.sub(a_is_expected).relate(a_ty, b_ty),
             SupertypeOf => {
-                self.sub(a_is_expected).relate_with_variance(ty::Contravariant, &a_ty, &b_ty)
+                self.sub(a_is_expected).relate_with_variance(ty::Contravariant, a_ty, b_ty)
             }
         }?;
 
@@ -379,7 +379,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
             param_env: self.param_env,
         };
 
-        let ty = match generalize.relate(&ty, &ty) {
+        let ty = match generalize.relate(ty, ty) {
             Ok(ty) => ty,
             Err(e) => {
                 debug!("generalize: failure {:?}", e);
@@ -490,8 +490,8 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
 
     fn binders<T>(
         &mut self,
-        a: &ty::Binder<T>,
-        b: &ty::Binder<T>,
+        a: ty::Binder<T>,
+        b: ty::Binder<T>,
     ) -> RelateResult<'tcx, ty::Binder<T>>
     where
         T: Relate<'tcx>,
@@ -519,8 +519,8 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         variance: ty::Variance,
-        a: &T,
-        b: &T,
+        a: T,
+        b: T,
     ) -> RelateResult<'tcx, T> {
         let old_ambient_variance = self.ambient_variance;
         self.ambient_variance = self.ambient_variance.xform(variance);
@@ -552,7 +552,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
                     match probe {
                         TypeVariableValue::Known { value: u } => {
                             debug!("generalize: known value {:?}", u);
-                            self.relate(&u, &u)
+                            self.relate(u, u)
                         }
                         TypeVariableValue::Unknown { universe } => {
                             match self.ambient_variance {
@@ -655,7 +655,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
                 let variable_table = &mut inner.const_unification_table();
                 let var_value = variable_table.probe_value(vid);
                 match var_value.val {
-                    ConstVariableValue::Known { value: u } => self.relate(&u, &u),
+                    ConstVariableValue::Known { value: u } => self.relate(u, u),
                     ConstVariableValue::Unknown { universe } => {
                         if self.for_universe.can_name(universe) {
                             Ok(c)
diff --git a/src/librustc_infer/infer/equate.rs b/src/librustc_infer/infer/equate.rs
index e3cafb82719dd..7de752d1de0db 100644
--- a/src/librustc_infer/infer/equate.rs
+++ b/src/librustc_infer/infer/equate.rs
@@ -59,8 +59,8 @@ impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> {
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         _: ty::Variance,
-        a: &T,
-        b: &T,
+        a: T,
+        b: T,
     ) -> RelateResult<'tcx, T> {
         self.relate(a, b)
     }
@@ -124,8 +124,8 @@ impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> {
 
     fn binders<T>(
         &mut self,
-        a: &ty::Binder<T>,
-        b: &ty::Binder<T>,
+        a: ty::Binder<T>,
+        b: ty::Binder<T>,
     ) -> RelateResult<'tcx, ty::Binder<T>>
     where
         T: Relate<'tcx>,
@@ -136,7 +136,7 @@ impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> {
         } else {
             // Fast path for the common case.
             self.relate(a.skip_binder(), b.skip_binder())?;
-            Ok(a.clone())
+            Ok(a)
         }
     }
 }
diff --git a/src/librustc_infer/infer/glb.rs b/src/librustc_infer/infer/glb.rs
index ec219a95b9441..8a0ab52f38306 100644
--- a/src/librustc_infer/infer/glb.rs
+++ b/src/librustc_infer/infer/glb.rs
@@ -43,8 +43,8 @@ impl TypeRelation<'tcx> for Glb<'combine, 'infcx, 'tcx> {
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         variance: ty::Variance,
-        a: &T,
-        b: &T,
+        a: T,
+        b: T,
     ) -> RelateResult<'tcx, T> {
         match variance {
             ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b),
@@ -85,8 +85,8 @@ impl TypeRelation<'tcx> for Glb<'combine, 'infcx, 'tcx> {
 
     fn binders<T>(
         &mut self,
-        a: &ty::Binder<T>,
-        b: &ty::Binder<T>,
+        a: ty::Binder<T>,
+        b: ty::Binder<T>,
     ) -> RelateResult<'tcx, ty::Binder<T>>
     where
         T: Relate<'tcx>,
@@ -112,8 +112,8 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx,
 
     fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
         let mut sub = self.fields.sub(self.a_is_expected);
-        sub.relate(&v, &a)?;
-        sub.relate(&v, &b)?;
+        sub.relate(v, a)?;
+        sub.relate(v, b)?;
         Ok(())
     }
 }
diff --git a/src/librustc_infer/infer/higher_ranked/mod.rs b/src/librustc_infer/infer/higher_ranked/mod.rs
index b6251e34008a3..ea19dff7db125 100644
--- a/src/librustc_infer/infer/higher_ranked/mod.rs
+++ b/src/librustc_infer/infer/higher_ranked/mod.rs
@@ -11,8 +11,8 @@ use rustc_middle::ty::{self, Binder, TypeFoldable};
 impl<'a, 'tcx> CombineFields<'a, 'tcx> {
     pub fn higher_ranked_sub<T>(
         &mut self,
-        a: &Binder<T>,
-        b: &Binder<T>,
+        a: Binder<T>,
+        b: Binder<T>,
         a_is_expected: bool,
     ) -> RelateResult<'tcx, Binder<T>>
     where
@@ -33,20 +33,20 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> {
         self.infcx.commit_if_ok(|_| {
             // First, we instantiate each bound region in the supertype with a
             // fresh placeholder region.
-            let (b_prime, _) = self.infcx.replace_bound_vars_with_placeholders(b);
+            let (b_prime, _) = self.infcx.replace_bound_vars_with_placeholders(&b);
 
             // Next, we instantiate each bound region in the subtype
             // with a fresh region variable. These region variables --
             // but no other pre-existing region variables -- can name
             // the placeholders.
             let (a_prime, _) =
-                self.infcx.replace_bound_vars_with_fresh_vars(span, HigherRankedType, a);
+                self.infcx.replace_bound_vars_with_fresh_vars(span, HigherRankedType, &a);
 
             debug!("a_prime={:?}", a_prime);
             debug!("b_prime={:?}", b_prime);
 
             // Compare types now that bound regions have been replaced.
-            let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?;
+            let result = self.sub(a_is_expected).relate(a_prime, b_prime)?;
 
             debug!("higher_ranked_sub: OK result={:?}", result);
 
diff --git a/src/librustc_infer/infer/lub.rs b/src/librustc_infer/infer/lub.rs
index a0453db2cb499..3e2ea3d0f8fbf 100644
--- a/src/librustc_infer/infer/lub.rs
+++ b/src/librustc_infer/infer/lub.rs
@@ -43,8 +43,8 @@ impl TypeRelation<'tcx> for Lub<'combine, 'infcx, 'tcx> {
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         variance: ty::Variance,
-        a: &T,
-        b: &T,
+        a: T,
+        b: T,
     ) -> RelateResult<'tcx, T> {
         match variance {
             ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b),
@@ -85,8 +85,8 @@ impl TypeRelation<'tcx> for Lub<'combine, 'infcx, 'tcx> {
 
     fn binders<T>(
         &mut self,
-        a: &ty::Binder<T>,
-        b: &ty::Binder<T>,
+        a: ty::Binder<T>,
+        b: ty::Binder<T>,
     ) -> RelateResult<'tcx, ty::Binder<T>>
     where
         T: Relate<'tcx>,
@@ -97,7 +97,7 @@ impl TypeRelation<'tcx> for Lub<'combine, 'infcx, 'tcx> {
         // very challenging, switch to invariance. This is obviously
         // overly conservative but works ok in practice.
         self.relate_with_variance(ty::Variance::Invariant, a, b)?;
-        Ok(a.clone())
+        Ok(a)
     }
 }
 
@@ -118,8 +118,8 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx,
 
     fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
         let mut sub = self.fields.sub(self.a_is_expected);
-        sub.relate(&a, &v)?;
-        sub.relate(&b, &v)?;
+        sub.relate(a, v)?;
+        sub.relate(b, v)?;
         Ok(())
     }
 }
diff --git a/src/librustc_infer/infer/nll_relate/mod.rs b/src/librustc_infer/infer/nll_relate/mod.rs
index 2350c28dfaaff..cb1f1c08d88f8 100644
--- a/src/librustc_infer/infer/nll_relate/mod.rs
+++ b/src/librustc_infer/infer/nll_relate/mod.rs
@@ -161,7 +161,7 @@ where
 
     fn create_scope(
         &mut self,
-        value: &ty::Binder<impl TypeFoldable<'tcx>>,
+        value: ty::Binder<impl Relate<'tcx>>,
         universally_quantified: UniversallyQuantified,
     ) -> BoundRegionScope<'tcx> {
         let mut scope = BoundRegionScope::default();
@@ -369,7 +369,7 @@ where
             universe,
         };
 
-        generalizer.relate(&value, &value)
+        generalizer.relate(value, value)
     }
 }
 
@@ -495,8 +495,8 @@ where
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         variance: ty::Variance,
-        a: &T,
-        b: &T,
+        a: T,
+        b: T,
     ) -> RelateResult<'tcx, T> {
         debug!("relate_with_variance(variance={:?}, a={:?}, b={:?})", variance, a, b);
 
@@ -613,8 +613,8 @@ where
 
     fn binders<T>(
         &mut self,
-        a: &ty::Binder<T>,
-        b: &ty::Binder<T>,
+        a: ty::Binder<T>,
+        b: ty::Binder<T>,
     ) -> RelateResult<'tcx, ty::Binder<T>>
     where
         T: Relate<'tcx>,
@@ -640,11 +640,10 @@ where
 
         debug!("binders({:?}: {:?}, ambient_variance={:?})", a, b, self.ambient_variance);
 
-        if !a.skip_binder().has_escaping_bound_vars() && !b.skip_binder().has_escaping_bound_vars()
-        {
+        if let (Some(a), Some(b)) = (a.no_bound_vars(), b.no_bound_vars()) {
             // Fast path for the common case.
-            self.relate(a.skip_binder(), b.skip_binder())?;
-            return Ok(a.clone());
+            self.relate(a, b)?;
+            return Ok(ty::Binder::bind(a));
         }
 
         if self.ambient_covariance() {
@@ -839,8 +838,8 @@ where
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         variance: ty::Variance,
-        a: &T,
-        b: &T,
+        a: T,
+        b: T,
     ) -> RelateResult<'tcx, T> {
         debug!(
             "TypeGeneralizer::relate_with_variance(variance={:?}, a={:?}, b={:?})",
@@ -890,7 +889,7 @@ where
                     match variables.probe(vid) {
                         TypeVariableValue::Known { value: u } => {
                             drop(variables);
-                            self.relate(&u, &u)
+                            self.relate(u, u)
                         }
                         TypeVariableValue::Unknown { universe: _universe } => {
                             if self.ambient_variance == ty::Bivariant {
@@ -984,7 +983,7 @@ where
                 let variable_table = &mut inner.const_unification_table();
                 let var_value = variable_table.probe_value(vid);
                 match var_value.val.known() {
-                    Some(u) => self.relate(&u, &u),
+                    Some(u) => self.relate(u, u),
                     None => {
                         let new_var_id = variable_table.new_key(ConstVarValue {
                             origin: var_value.origin,
@@ -1001,8 +1000,8 @@ where
 
     fn binders<T>(
         &mut self,
-        a: &ty::Binder<T>,
-        _: &ty::Binder<T>,
+        a: ty::Binder<T>,
+        _: ty::Binder<T>,
     ) -> RelateResult<'tcx, ty::Binder<T>>
     where
         T: Relate<'tcx>,
diff --git a/src/librustc_infer/infer/sub.rs b/src/librustc_infer/infer/sub.rs
index 90962d210b5b4..d190f7e434298 100644
--- a/src/librustc_infer/infer/sub.rs
+++ b/src/librustc_infer/infer/sub.rs
@@ -62,8 +62,8 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> {
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         variance: ty::Variance,
-        a: &T,
-        b: &T,
+        a: T,
+        b: T,
     ) -> RelateResult<'tcx, T> {
         match variance {
             ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b),
@@ -162,8 +162,8 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> {
 
     fn binders<T>(
         &mut self,
-        a: &ty::Binder<T>,
-        b: &ty::Binder<T>,
+        a: ty::Binder<T>,
+        b: ty::Binder<T>,
     ) -> RelateResult<'tcx, ty::Binder<T>>
     where
         T: Relate<'tcx>,
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 36d2954ac6ef7..d55cbbe19c279 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -911,7 +911,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutableTransmutes {
                 }
                 let sig = cx.tables().node_type(expr.hir_id).fn_sig(cx.tcx);
                 let from = sig.inputs().skip_binder()[0];
-                let to = *sig.output().skip_binder();
+                let to = sig.output().skip_binder();
                 return Some((from, to));
             }
             None
diff --git a/src/librustc_middle/ich/impls_ty.rs b/src/librustc_middle/ich/impls_ty.rs
index ef6247881c0be..8f15c99f951fe 100644
--- a/src/librustc_middle/ich/impls_ty.rs
+++ b/src/librustc_middle/ich/impls_ty.rs
@@ -123,7 +123,7 @@ where
     T: HashStable<StableHashingContext<'a>>,
 {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        self.skip_binder().hash_stable(hcx, hasher);
+        self.as_ref().skip_binder().hash_stable(hcx, hasher);
     }
 }
 
diff --git a/src/librustc_middle/lib.rs b/src/librustc_middle/lib.rs
index 676346fbebdd1..96b8ca27183ed 100644
--- a/src/librustc_middle/lib.rs
+++ b/src/librustc_middle/lib.rs
@@ -42,7 +42,7 @@
 #![feature(or_patterns)]
 #![feature(range_is_empty)]
 #![feature(min_specialization)]
-#![feature(track_caller)]
+#![cfg_attr(bootstrap, feature(track_caller))]
 #![feature(trusted_len)]
 #![feature(stmt_expr_attributes)]
 #![feature(test)]
diff --git a/src/librustc_middle/mir/mod.rs b/src/librustc_middle/mir/mod.rs
index 0ed0d9050078c..ae59f8c542d8c 100644
--- a/src/librustc_middle/mir/mod.rs
+++ b/src/librustc_middle/mir/mod.rs
@@ -19,7 +19,6 @@ use rustc_target::abi::VariantIdx;
 
 use polonius_engine::Atom;
 pub use rustc_ast::ast::Mutability;
-use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::graph::dominators::{dominators, Dominators};
 use rustc_data_structures::graph::{self, GraphSuccessors};
@@ -45,6 +44,8 @@ pub mod mono;
 mod predecessors;
 mod query;
 pub mod tcx;
+pub mod terminator;
+pub use terminator::*;
 pub mod traversal;
 mod type_foldable;
 pub mod visit;
@@ -1046,191 +1047,6 @@ pub struct BasicBlockData<'tcx> {
     pub is_cleanup: bool,
 }
 
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
-pub struct Terminator<'tcx> {
-    pub source_info: SourceInfo,
-    pub kind: TerminatorKind<'tcx>,
-}
-
-#[derive(Clone, RustcEncodable, RustcDecodable, HashStable, PartialEq)]
-pub enum TerminatorKind<'tcx> {
-    /// Block should have one successor in the graph; we jump there.
-    Goto { target: BasicBlock },
-
-    /// Operand evaluates to an integer; jump depending on its value
-    /// to one of the targets, and otherwise fallback to `otherwise`.
-    SwitchInt {
-        /// The discriminant value being tested.
-        discr: Operand<'tcx>,
-
-        /// The type of value being tested.
-        /// This is always the same as the type of `discr`.
-        /// FIXME: remove this redundant information. Currently, it is relied on by pretty-printing.
-        switch_ty: Ty<'tcx>,
-
-        /// Possible values. The locations to branch to in each case
-        /// are found in the corresponding indices from the `targets` vector.
-        values: Cow<'tcx, [u128]>,
-
-        /// Possible branch sites. The last element of this vector is used
-        /// for the otherwise branch, so targets.len() == values.len() + 1
-        /// should hold.
-        //
-        // This invariant is quite non-obvious and also could be improved.
-        // One way to make this invariant is to have something like this instead:
-        //
-        // branches: Vec<(ConstInt, BasicBlock)>,
-        // otherwise: Option<BasicBlock> // exhaustive if None
-        //
-        // However we’ve decided to keep this as-is until we figure a case
-        // where some other approach seems to be strictly better than other.
-        targets: Vec<BasicBlock>,
-    },
-
-    /// Indicates that the landing pad is finished and unwinding should
-    /// continue. Emitted by `build::scope::diverge_cleanup`.
-    Resume,
-
-    /// Indicates that the landing pad is finished and that the process
-    /// should abort. Used to prevent unwinding for foreign items.
-    Abort,
-
-    /// Indicates a normal return. The return place should have
-    /// been filled in before this executes. This can occur multiple times
-    /// in different basic blocks.
-    Return,
-
-    /// Indicates a terminator that can never be reached.
-    Unreachable,
-
-    /// Drop the `Place`.
-    Drop { place: Place<'tcx>, target: BasicBlock, unwind: Option<BasicBlock> },
-
-    /// Drop the `Place` and assign the new value over it. This ensures
-    /// that the assignment to `P` occurs *even if* the destructor for
-    /// place unwinds. Its semantics are best explained by the
-    /// elaboration:
-    ///
-    /// ```
-    /// BB0 {
-    ///   DropAndReplace(P <- V, goto BB1, unwind BB2)
-    /// }
-    /// ```
-    ///
-    /// becomes
-    ///
-    /// ```
-    /// BB0 {
-    ///   Drop(P, goto BB1, unwind BB2)
-    /// }
-    /// BB1 {
-    ///   // P is now uninitialized
-    ///   P <- V
-    /// }
-    /// BB2 {
-    ///   // P is now uninitialized -- its dtor panicked
-    ///   P <- V
-    /// }
-    /// ```
-    DropAndReplace {
-        place: Place<'tcx>,
-        value: Operand<'tcx>,
-        target: BasicBlock,
-        unwind: Option<BasicBlock>,
-    },
-
-    /// Block ends with a call of a converging function.
-    Call {
-        /// The function that’s being called.
-        func: Operand<'tcx>,
-        /// Arguments the function is called with.
-        /// These are owned by the callee, which is free to modify them.
-        /// This allows the memory occupied by "by-value" arguments to be
-        /// reused across function calls without duplicating the contents.
-        args: Vec<Operand<'tcx>>,
-        /// Destination for the return value. If some, the call is converging.
-        destination: Option<(Place<'tcx>, BasicBlock)>,
-        /// Cleanups to be done if the call unwinds.
-        cleanup: Option<BasicBlock>,
-        /// `true` if this is from a call in HIR rather than from an overloaded
-        /// operator. True for overloaded function call.
-        from_hir_call: bool,
-        /// This `Span` is the span of the function, without the dot and receiver
-        /// (e.g. `foo(a, b)` in `x.foo(a, b)`
-        fn_span: Span,
-    },
-
-    /// Jump to the target if the condition has the expected value,
-    /// otherwise panic with a message and a cleanup target.
-    Assert {
-        cond: Operand<'tcx>,
-        expected: bool,
-        msg: AssertMessage<'tcx>,
-        target: BasicBlock,
-        cleanup: Option<BasicBlock>,
-    },
-
-    /// A suspend point.
-    Yield {
-        /// The value to return.
-        value: Operand<'tcx>,
-        /// Where to resume to.
-        resume: BasicBlock,
-        /// The place to store the resume argument in.
-        resume_arg: Place<'tcx>,
-        /// Cleanup to be done if the generator is dropped at this suspend point.
-        drop: Option<BasicBlock>,
-    },
-
-    /// Indicates the end of the dropping of a generator.
-    GeneratorDrop,
-
-    /// A block where control flow only ever takes one real path, but borrowck
-    /// needs to be more conservative.
-    FalseEdge {
-        /// The target normal control flow will take.
-        real_target: BasicBlock,
-        /// A block control flow could conceptually jump to, but won't in
-        /// practice.
-        imaginary_target: BasicBlock,
-    },
-    /// A terminator for blocks that only take one path in reality, but where we
-    /// reserve the right to unwind in borrowck, even if it won't happen in practice.
-    /// This can arise in infinite loops with no function calls for example.
-    FalseUnwind {
-        /// The target normal control flow will take.
-        real_target: BasicBlock,
-        /// The imaginary cleanup block link. This particular path will never be taken
-        /// in practice, but in order to avoid fragility we want to always
-        /// consider it in borrowck. We don't want to accept programs which
-        /// pass borrowck only when `panic=abort` or some assertions are disabled
-        /// due to release vs. debug mode builds. This needs to be an `Option` because
-        /// of the `remove_noop_landing_pads` and `no_landing_pads` passes.
-        unwind: Option<BasicBlock>,
-    },
-
-    /// Block ends with an inline assembly block. This is a terminator since
-    /// inline assembly is allowed to diverge.
-    InlineAsm {
-        /// The template for the inline assembly, with placeholders.
-        template: &'tcx [InlineAsmTemplatePiece],
-
-        /// The operands for the inline assembly, as `Operand`s or `Place`s.
-        operands: Vec<InlineAsmOperand<'tcx>>,
-
-        /// Miscellaneous options for the inline assembly.
-        options: InlineAsmOptions,
-
-        /// Source spans for each line of the inline assembly code. These are
-        /// used to map assembler errors back to the line in the source code.
-        line_spans: &'tcx [Span],
-
-        /// Destination block after the inline assembly returns, unless it is
-        /// diverging (InlineAsmOptions::NORETURN).
-        destination: Option<BasicBlock>,
-    },
-}
-
 /// Information about an assertion failure.
 #[derive(Clone, RustcEncodable, RustcDecodable, HashStable, PartialEq)]
 pub enum AssertKind<O> {
@@ -1279,149 +1095,6 @@ pub type Successors<'a> =
 pub type SuccessorsMut<'a> =
     iter::Chain<option::IntoIter<&'a mut BasicBlock>, slice::IterMut<'a, BasicBlock>>;
 
-impl<'tcx> Terminator<'tcx> {
-    pub fn successors(&self) -> Successors<'_> {
-        self.kind.successors()
-    }
-
-    pub fn successors_mut(&mut self) -> SuccessorsMut<'_> {
-        self.kind.successors_mut()
-    }
-
-    pub fn unwind(&self) -> Option<&Option<BasicBlock>> {
-        self.kind.unwind()
-    }
-
-    pub fn unwind_mut(&mut self) -> Option<&mut Option<BasicBlock>> {
-        self.kind.unwind_mut()
-    }
-}
-
-impl<'tcx> TerminatorKind<'tcx> {
-    pub fn if_(
-        tcx: TyCtxt<'tcx>,
-        cond: Operand<'tcx>,
-        t: BasicBlock,
-        f: BasicBlock,
-    ) -> TerminatorKind<'tcx> {
-        static BOOL_SWITCH_FALSE: &[u128] = &[0];
-        TerminatorKind::SwitchInt {
-            discr: cond,
-            switch_ty: tcx.types.bool,
-            values: From::from(BOOL_SWITCH_FALSE),
-            targets: vec![f, t],
-        }
-    }
-
-    pub fn successors(&self) -> Successors<'_> {
-        use self::TerminatorKind::*;
-        match *self {
-            Resume
-            | Abort
-            | GeneratorDrop
-            | Return
-            | Unreachable
-            | Call { destination: None, cleanup: None, .. }
-            | InlineAsm { destination: None, .. } => None.into_iter().chain(&[]),
-            Goto { target: ref t }
-            | Call { destination: None, cleanup: Some(ref t), .. }
-            | Call { destination: Some((_, ref t)), cleanup: None, .. }
-            | Yield { resume: ref t, drop: None, .. }
-            | DropAndReplace { target: ref t, unwind: None, .. }
-            | Drop { target: ref t, unwind: None, .. }
-            | Assert { target: ref t, cleanup: None, .. }
-            | FalseUnwind { real_target: ref t, unwind: None }
-            | InlineAsm { destination: Some(ref t), .. } => Some(t).into_iter().chain(&[]),
-            Call { destination: Some((_, ref t)), cleanup: Some(ref u), .. }
-            | Yield { resume: ref t, drop: Some(ref u), .. }
-            | DropAndReplace { target: ref t, unwind: Some(ref u), .. }
-            | Drop { target: ref t, unwind: Some(ref u), .. }
-            | Assert { target: ref t, cleanup: Some(ref u), .. }
-            | FalseUnwind { real_target: ref t, unwind: Some(ref u) } => {
-                Some(t).into_iter().chain(slice::from_ref(u))
-            }
-            SwitchInt { ref targets, .. } => None.into_iter().chain(&targets[..]),
-            FalseEdge { ref real_target, ref imaginary_target } => {
-                Some(real_target).into_iter().chain(slice::from_ref(imaginary_target))
-            }
-        }
-    }
-
-    pub fn successors_mut(&mut self) -> SuccessorsMut<'_> {
-        use self::TerminatorKind::*;
-        match *self {
-            Resume
-            | Abort
-            | GeneratorDrop
-            | Return
-            | Unreachable
-            | Call { destination: None, cleanup: None, .. }
-            | InlineAsm { destination: None, .. } => None.into_iter().chain(&mut []),
-            Goto { target: ref mut t }
-            | Call { destination: None, cleanup: Some(ref mut t), .. }
-            | Call { destination: Some((_, ref mut t)), cleanup: None, .. }
-            | Yield { resume: ref mut t, drop: None, .. }
-            | DropAndReplace { target: ref mut t, unwind: None, .. }
-            | Drop { target: ref mut t, unwind: None, .. }
-            | Assert { target: ref mut t, cleanup: None, .. }
-            | FalseUnwind { real_target: ref mut t, unwind: None }
-            | InlineAsm { destination: Some(ref mut t), .. } => Some(t).into_iter().chain(&mut []),
-            Call { destination: Some((_, ref mut t)), cleanup: Some(ref mut u), .. }
-            | Yield { resume: ref mut t, drop: Some(ref mut u), .. }
-            | DropAndReplace { target: ref mut t, unwind: Some(ref mut u), .. }
-            | Drop { target: ref mut t, unwind: Some(ref mut u), .. }
-            | Assert { target: ref mut t, cleanup: Some(ref mut u), .. }
-            | FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) } => {
-                Some(t).into_iter().chain(slice::from_mut(u))
-            }
-            SwitchInt { ref mut targets, .. } => None.into_iter().chain(&mut targets[..]),
-            FalseEdge { ref mut real_target, ref mut imaginary_target } => {
-                Some(real_target).into_iter().chain(slice::from_mut(imaginary_target))
-            }
-        }
-    }
-
-    pub fn unwind(&self) -> Option<&Option<BasicBlock>> {
-        match *self {
-            TerminatorKind::Goto { .. }
-            | TerminatorKind::Resume
-            | TerminatorKind::Abort
-            | TerminatorKind::Return
-            | TerminatorKind::Unreachable
-            | TerminatorKind::GeneratorDrop
-            | TerminatorKind::Yield { .. }
-            | TerminatorKind::SwitchInt { .. }
-            | TerminatorKind::FalseEdge { .. }
-            | TerminatorKind::InlineAsm { .. } => None,
-            TerminatorKind::Call { cleanup: ref unwind, .. }
-            | TerminatorKind::Assert { cleanup: ref unwind, .. }
-            | TerminatorKind::DropAndReplace { ref unwind, .. }
-            | TerminatorKind::Drop { ref unwind, .. }
-            | TerminatorKind::FalseUnwind { ref unwind, .. } => Some(unwind),
-        }
-    }
-
-    pub fn unwind_mut(&mut self) -> Option<&mut Option<BasicBlock>> {
-        match *self {
-            TerminatorKind::Goto { .. }
-            | TerminatorKind::Resume
-            | TerminatorKind::Abort
-            | TerminatorKind::Return
-            | TerminatorKind::Unreachable
-            | TerminatorKind::GeneratorDrop
-            | TerminatorKind::Yield { .. }
-            | TerminatorKind::SwitchInt { .. }
-            | TerminatorKind::FalseEdge { .. }
-            | TerminatorKind::InlineAsm { .. } => None,
-            TerminatorKind::Call { cleanup: ref mut unwind, .. }
-            | TerminatorKind::Assert { cleanup: ref mut unwind, .. }
-            | TerminatorKind::DropAndReplace { ref mut unwind, .. }
-            | TerminatorKind::Drop { ref mut unwind, .. }
-            | TerminatorKind::FalseUnwind { ref mut unwind, .. } => Some(unwind),
-        }
-    }
-}
-
 impl<'tcx> BasicBlockData<'tcx> {
     pub fn new(terminator: Option<Terminator<'tcx>>) -> BasicBlockData<'tcx> {
         BasicBlockData { statements: vec![], terminator, is_cleanup: false }
@@ -1628,169 +1301,6 @@ impl<O: fmt::Debug> fmt::Debug for AssertKind<O> {
     }
 }
 
-impl<'tcx> Debug for TerminatorKind<'tcx> {
-    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
-        self.fmt_head(fmt)?;
-        let successor_count = self.successors().count();
-        let labels = self.fmt_successor_labels();
-        assert_eq!(successor_count, labels.len());
-
-        match successor_count {
-            0 => Ok(()),
-
-            1 => write!(fmt, " -> {:?}", self.successors().next().unwrap()),
-
-            _ => {
-                write!(fmt, " -> [")?;
-                for (i, target) in self.successors().enumerate() {
-                    if i > 0 {
-                        write!(fmt, ", ")?;
-                    }
-                    write!(fmt, "{}: {:?}", labels[i], target)?;
-                }
-                write!(fmt, "]")
-            }
-        }
-    }
-}
-
-impl<'tcx> TerminatorKind<'tcx> {
-    /// Writes the "head" part of the terminator; that is, its name and the data it uses to pick the
-    /// successor basic block, if any. The only information not included is the list of possible
-    /// successors, which may be rendered differently between the text and the graphviz format.
-    pub fn fmt_head<W: Write>(&self, fmt: &mut W) -> fmt::Result {
-        use self::TerminatorKind::*;
-        match self {
-            Goto { .. } => write!(fmt, "goto"),
-            SwitchInt { discr, .. } => write!(fmt, "switchInt({:?})", discr),
-            Return => write!(fmt, "return"),
-            GeneratorDrop => write!(fmt, "generator_drop"),
-            Resume => write!(fmt, "resume"),
-            Abort => write!(fmt, "abort"),
-            Yield { value, resume_arg, .. } => write!(fmt, "{:?} = yield({:?})", resume_arg, value),
-            Unreachable => write!(fmt, "unreachable"),
-            Drop { place, .. } => write!(fmt, "drop({:?})", place),
-            DropAndReplace { place, value, .. } => {
-                write!(fmt, "replace({:?} <- {:?})", place, value)
-            }
-            Call { func, args, destination, .. } => {
-                if let Some((destination, _)) = destination {
-                    write!(fmt, "{:?} = ", destination)?;
-                }
-                write!(fmt, "{:?}(", func)?;
-                for (index, arg) in args.iter().enumerate() {
-                    if index > 0 {
-                        write!(fmt, ", ")?;
-                    }
-                    write!(fmt, "{:?}", arg)?;
-                }
-                write!(fmt, ")")
-            }
-            Assert { cond, expected, msg, .. } => {
-                write!(fmt, "assert(")?;
-                if !expected {
-                    write!(fmt, "!")?;
-                }
-                write!(fmt, "{:?}, ", cond)?;
-                msg.fmt_assert_args(fmt)?;
-                write!(fmt, ")")
-            }
-            FalseEdge { .. } => write!(fmt, "falseEdge"),
-            FalseUnwind { .. } => write!(fmt, "falseUnwind"),
-            InlineAsm { template, ref operands, options, .. } => {
-                write!(fmt, "asm!(\"{}\"", InlineAsmTemplatePiece::to_string(template))?;
-                for op in operands {
-                    write!(fmt, ", ")?;
-                    let print_late = |&late| if late { "late" } else { "" };
-                    match op {
-                        InlineAsmOperand::In { reg, value } => {
-                            write!(fmt, "in({}) {:?}", reg, value)?;
-                        }
-                        InlineAsmOperand::Out { reg, late, place: Some(place) } => {
-                            write!(fmt, "{}out({}) {:?}", print_late(late), reg, place)?;
-                        }
-                        InlineAsmOperand::Out { reg, late, place: None } => {
-                            write!(fmt, "{}out({}) _", print_late(late), reg)?;
-                        }
-                        InlineAsmOperand::InOut {
-                            reg,
-                            late,
-                            in_value,
-                            out_place: Some(out_place),
-                        } => {
-                            write!(
-                                fmt,
-                                "in{}out({}) {:?} => {:?}",
-                                print_late(late),
-                                reg,
-                                in_value,
-                                out_place
-                            )?;
-                        }
-                        InlineAsmOperand::InOut { reg, late, in_value, out_place: None } => {
-                            write!(fmt, "in{}out({}) {:?} => _", print_late(late), reg, in_value)?;
-                        }
-                        InlineAsmOperand::Const { value } => {
-                            write!(fmt, "const {:?}", value)?;
-                        }
-                        InlineAsmOperand::SymFn { value } => {
-                            write!(fmt, "sym_fn {:?}", value)?;
-                        }
-                        InlineAsmOperand::SymStatic { def_id } => {
-                            write!(fmt, "sym_static {:?}", def_id)?;
-                        }
-                    }
-                }
-                write!(fmt, ", options({:?}))", options)
-            }
-        }
-    }
-
-    /// Returns the list of labels for the edges to the successor basic blocks.
-    pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> {
-        use self::TerminatorKind::*;
-        match *self {
-            Return | Resume | Abort | Unreachable | GeneratorDrop => vec![],
-            Goto { .. } => vec!["".into()],
-            SwitchInt { ref values, switch_ty, .. } => ty::tls::with(|tcx| {
-                let param_env = ty::ParamEnv::empty();
-                let switch_ty = tcx.lift(&switch_ty).unwrap();
-                let size = tcx.layout_of(param_env.and(switch_ty)).unwrap().size;
-                values
-                    .iter()
-                    .map(|&u| {
-                        ty::Const::from_scalar(tcx, Scalar::from_uint(u, size), switch_ty)
-                            .to_string()
-                            .into()
-                    })
-                    .chain(iter::once("otherwise".into()))
-                    .collect()
-            }),
-            Call { destination: Some(_), cleanup: Some(_), .. } => {
-                vec!["return".into(), "unwind".into()]
-            }
-            Call { destination: Some(_), cleanup: None, .. } => vec!["return".into()],
-            Call { destination: None, cleanup: Some(_), .. } => vec!["unwind".into()],
-            Call { destination: None, cleanup: None, .. } => vec![],
-            Yield { drop: Some(_), .. } => vec!["resume".into(), "drop".into()],
-            Yield { drop: None, .. } => vec!["resume".into()],
-            DropAndReplace { unwind: None, .. } | Drop { unwind: None, .. } => {
-                vec!["return".into()]
-            }
-            DropAndReplace { unwind: Some(_), .. } | Drop { unwind: Some(_), .. } => {
-                vec!["return".into(), "unwind".into()]
-            }
-            Assert { cleanup: None, .. } => vec!["".into()],
-            Assert { .. } => vec!["success".into(), "unwind".into()],
-            FalseEdge { .. } => vec!["real".into(), "imaginary".into()],
-            FalseUnwind { unwind: Some(_), .. } => vec!["real".into(), "cleanup".into()],
-            FalseUnwind { unwind: None, .. } => vec!["real".into()],
-            InlineAsm { destination: Some(_), .. } => vec!["".into()],
-            InlineAsm { destination: None, .. } => vec![],
-        }
-    }
-}
-
 ///////////////////////////////////////////////////////////////////////////
 // Statements
 
diff --git a/src/librustc_middle/mir/terminator/mod.rs b/src/librustc_middle/mir/terminator/mod.rs
new file mode 100644
index 0000000000000..1f5041141d55b
--- /dev/null
+++ b/src/librustc_middle/mir/terminator/mod.rs
@@ -0,0 +1,507 @@
+use crate::mir::interpret::Scalar;
+use crate::ty::{self, Ty, TyCtxt};
+use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece};
+
+use super::{
+    AssertMessage, BasicBlock, InlineAsmOperand, Operand, Place, SourceInfo, Successors,
+    SuccessorsMut,
+};
+pub use rustc_ast::ast::Mutability;
+use rustc_macros::HashStable;
+use rustc_span::Span;
+use std::borrow::Cow;
+use std::fmt::{self, Debug, Formatter, Write};
+use std::iter;
+use std::slice;
+
+pub use super::query::*;
+
+#[derive(Clone, RustcEncodable, RustcDecodable, HashStable, PartialEq)]
+pub enum TerminatorKind<'tcx> {
+    /// Block should have one successor in the graph; we jump there.
+    Goto { target: BasicBlock },
+
+    /// Operand evaluates to an integer; jump depending on its value
+    /// to one of the targets, and otherwise fallback to `otherwise`.
+    SwitchInt {
+        /// The discriminant value being tested.
+        discr: Operand<'tcx>,
+
+        /// The type of value being tested.
+        /// This is always the same as the type of `discr`.
+        /// FIXME: remove this redundant information. Currently, it is relied on by pretty-printing.
+        switch_ty: Ty<'tcx>,
+
+        /// Possible values. The locations to branch to in each case
+        /// are found in the corresponding indices from the `targets` vector.
+        values: Cow<'tcx, [u128]>,
+
+        /// Possible branch sites. The last element of this vector is used
+        /// for the otherwise branch, so targets.len() == values.len() + 1
+        /// should hold.
+        //
+        // This invariant is quite non-obvious and also could be improved.
+        // One way to make this invariant is to have something like this instead:
+        //
+        // branches: Vec<(ConstInt, BasicBlock)>,
+        // otherwise: Option<BasicBlock> // exhaustive if None
+        //
+        // However we’ve decided to keep this as-is until we figure a case
+        // where some other approach seems to be strictly better than other.
+        targets: Vec<BasicBlock>,
+    },
+
+    /// Indicates that the landing pad is finished and unwinding should
+    /// continue. Emitted by `build::scope::diverge_cleanup`.
+    Resume,
+
+    /// Indicates that the landing pad is finished and that the process
+    /// should abort. Used to prevent unwinding for foreign items.
+    Abort,
+
+    /// Indicates a normal return. The return place should have
+    /// been filled in before this executes. This can occur multiple times
+    /// in different basic blocks.
+    Return,
+
+    /// Indicates a terminator that can never be reached.
+    Unreachable,
+
+    /// Drop the `Place`.
+    Drop { place: Place<'tcx>, target: BasicBlock, unwind: Option<BasicBlock> },
+
+    /// Drop the `Place` and assign the new value over it. This ensures
+    /// that the assignment to `P` occurs *even if* the destructor for
+    /// place unwinds. Its semantics are best explained by the
+    /// elaboration:
+    ///
+    /// ```
+    /// BB0 {
+    ///   DropAndReplace(P <- V, goto BB1, unwind BB2)
+    /// }
+    /// ```
+    ///
+    /// becomes
+    ///
+    /// ```
+    /// BB0 {
+    ///   Drop(P, goto BB1, unwind BB2)
+    /// }
+    /// BB1 {
+    ///   // P is now uninitialized
+    ///   P <- V
+    /// }
+    /// BB2 {
+    ///   // P is now uninitialized -- its dtor panicked
+    ///   P <- V
+    /// }
+    /// ```
+    DropAndReplace {
+        place: Place<'tcx>,
+        value: Operand<'tcx>,
+        target: BasicBlock,
+        unwind: Option<BasicBlock>,
+    },
+
+    /// Block ends with a call of a converging function.
+    Call {
+        /// The function that’s being called.
+        func: Operand<'tcx>,
+        /// Arguments the function is called with.
+        /// These are owned by the callee, which is free to modify them.
+        /// This allows the memory occupied by "by-value" arguments to be
+        /// reused across function calls without duplicating the contents.
+        args: Vec<Operand<'tcx>>,
+        /// Destination for the return value. If some, the call is converging.
+        destination: Option<(Place<'tcx>, BasicBlock)>,
+        /// Cleanups to be done if the call unwinds.
+        cleanup: Option<BasicBlock>,
+        /// `true` if this is from a call in HIR rather than from an overloaded
+        /// operator. True for overloaded function call.
+        from_hir_call: bool,
+        /// This `Span` is the span of the function, without the dot and receiver
+        /// (e.g. `foo(a, b)` in `x.foo(a, b)`
+        fn_span: Span,
+    },
+
+    /// Jump to the target if the condition has the expected value,
+    /// otherwise panic with a message and a cleanup target.
+    Assert {
+        cond: Operand<'tcx>,
+        expected: bool,
+        msg: AssertMessage<'tcx>,
+        target: BasicBlock,
+        cleanup: Option<BasicBlock>,
+    },
+
+    /// A suspend point.
+    Yield {
+        /// The value to return.
+        value: Operand<'tcx>,
+        /// Where to resume to.
+        resume: BasicBlock,
+        /// The place to store the resume argument in.
+        resume_arg: Place<'tcx>,
+        /// Cleanup to be done if the generator is dropped at this suspend point.
+        drop: Option<BasicBlock>,
+    },
+
+    /// Indicates the end of the dropping of a generator.
+    GeneratorDrop,
+
+    /// A block where control flow only ever takes one real path, but borrowck
+    /// needs to be more conservative.
+    FalseEdge {
+        /// The target normal control flow will take.
+        real_target: BasicBlock,
+        /// A block control flow could conceptually jump to, but won't in
+        /// practice.
+        imaginary_target: BasicBlock,
+    },
+    /// A terminator for blocks that only take one path in reality, but where we
+    /// reserve the right to unwind in borrowck, even if it won't happen in practice.
+    /// This can arise in infinite loops with no function calls for example.
+    FalseUnwind {
+        /// The target normal control flow will take.
+        real_target: BasicBlock,
+        /// The imaginary cleanup block link. This particular path will never be taken
+        /// in practice, but in order to avoid fragility we want to always
+        /// consider it in borrowck. We don't want to accept programs which
+        /// pass borrowck only when `panic=abort` or some assertions are disabled
+        /// due to release vs. debug mode builds. This needs to be an `Option` because
+        /// of the `remove_noop_landing_pads` and `no_landing_pads` passes.
+        unwind: Option<BasicBlock>,
+    },
+
+    /// Block ends with an inline assembly block. This is a terminator since
+    /// inline assembly is allowed to diverge.
+    InlineAsm {
+        /// The template for the inline assembly, with placeholders.
+        template: &'tcx [InlineAsmTemplatePiece],
+
+        /// The operands for the inline assembly, as `Operand`s or `Place`s.
+        operands: Vec<InlineAsmOperand<'tcx>>,
+
+        /// Miscellaneous options for the inline assembly.
+        options: InlineAsmOptions,
+
+        /// Source spans for each line of the inline assembly code. These are
+        /// used to map assembler errors back to the line in the source code.
+        line_spans: &'tcx [Span],
+
+        /// Destination block after the inline assembly returns, unless it is
+        /// diverging (InlineAsmOptions::NORETURN).
+        destination: Option<BasicBlock>,
+    },
+}
+#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
+pub struct Terminator<'tcx> {
+    pub source_info: SourceInfo,
+    pub kind: TerminatorKind<'tcx>,
+}
+
+impl<'tcx> Terminator<'tcx> {
+    pub fn successors(&self) -> Successors<'_> {
+        self.kind.successors()
+    }
+
+    pub fn successors_mut(&mut self) -> SuccessorsMut<'_> {
+        self.kind.successors_mut()
+    }
+
+    pub fn unwind(&self) -> Option<&Option<BasicBlock>> {
+        self.kind.unwind()
+    }
+
+    pub fn unwind_mut(&mut self) -> Option<&mut Option<BasicBlock>> {
+        self.kind.unwind_mut()
+    }
+}
+
+impl<'tcx> TerminatorKind<'tcx> {
+    pub fn if_(
+        tcx: TyCtxt<'tcx>,
+        cond: Operand<'tcx>,
+        t: BasicBlock,
+        f: BasicBlock,
+    ) -> TerminatorKind<'tcx> {
+        static BOOL_SWITCH_FALSE: &[u128] = &[0];
+        TerminatorKind::SwitchInt {
+            discr: cond,
+            switch_ty: tcx.types.bool,
+            values: From::from(BOOL_SWITCH_FALSE),
+            targets: vec![f, t],
+        }
+    }
+
+    pub fn successors(&self) -> Successors<'_> {
+        use self::TerminatorKind::*;
+        match *self {
+            Resume
+            | Abort
+            | GeneratorDrop
+            | Return
+            | Unreachable
+            | Call { destination: None, cleanup: None, .. }
+            | InlineAsm { destination: None, .. } => None.into_iter().chain(&[]),
+            Goto { target: ref t }
+            | Call { destination: None, cleanup: Some(ref t), .. }
+            | Call { destination: Some((_, ref t)), cleanup: None, .. }
+            | Yield { resume: ref t, drop: None, .. }
+            | DropAndReplace { target: ref t, unwind: None, .. }
+            | Drop { target: ref t, unwind: None, .. }
+            | Assert { target: ref t, cleanup: None, .. }
+            | FalseUnwind { real_target: ref t, unwind: None }
+            | InlineAsm { destination: Some(ref t), .. } => Some(t).into_iter().chain(&[]),
+            Call { destination: Some((_, ref t)), cleanup: Some(ref u), .. }
+            | Yield { resume: ref t, drop: Some(ref u), .. }
+            | DropAndReplace { target: ref t, unwind: Some(ref u), .. }
+            | Drop { target: ref t, unwind: Some(ref u), .. }
+            | Assert { target: ref t, cleanup: Some(ref u), .. }
+            | FalseUnwind { real_target: ref t, unwind: Some(ref u) } => {
+                Some(t).into_iter().chain(slice::from_ref(u))
+            }
+            SwitchInt { ref targets, .. } => None.into_iter().chain(&targets[..]),
+            FalseEdge { ref real_target, ref imaginary_target } => {
+                Some(real_target).into_iter().chain(slice::from_ref(imaginary_target))
+            }
+        }
+    }
+
+    pub fn successors_mut(&mut self) -> SuccessorsMut<'_> {
+        use self::TerminatorKind::*;
+        match *self {
+            Resume
+            | Abort
+            | GeneratorDrop
+            | Return
+            | Unreachable
+            | Call { destination: None, cleanup: None, .. }
+            | InlineAsm { destination: None, .. } => None.into_iter().chain(&mut []),
+            Goto { target: ref mut t }
+            | Call { destination: None, cleanup: Some(ref mut t), .. }
+            | Call { destination: Some((_, ref mut t)), cleanup: None, .. }
+            | Yield { resume: ref mut t, drop: None, .. }
+            | DropAndReplace { target: ref mut t, unwind: None, .. }
+            | Drop { target: ref mut t, unwind: None, .. }
+            | Assert { target: ref mut t, cleanup: None, .. }
+            | FalseUnwind { real_target: ref mut t, unwind: None }
+            | InlineAsm { destination: Some(ref mut t), .. } => Some(t).into_iter().chain(&mut []),
+            Call { destination: Some((_, ref mut t)), cleanup: Some(ref mut u), .. }
+            | Yield { resume: ref mut t, drop: Some(ref mut u), .. }
+            | DropAndReplace { target: ref mut t, unwind: Some(ref mut u), .. }
+            | Drop { target: ref mut t, unwind: Some(ref mut u), .. }
+            | Assert { target: ref mut t, cleanup: Some(ref mut u), .. }
+            | FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) } => {
+                Some(t).into_iter().chain(slice::from_mut(u))
+            }
+            SwitchInt { ref mut targets, .. } => None.into_iter().chain(&mut targets[..]),
+            FalseEdge { ref mut real_target, ref mut imaginary_target } => {
+                Some(real_target).into_iter().chain(slice::from_mut(imaginary_target))
+            }
+        }
+    }
+
+    pub fn unwind(&self) -> Option<&Option<BasicBlock>> {
+        match *self {
+            TerminatorKind::Goto { .. }
+            | TerminatorKind::Resume
+            | TerminatorKind::Abort
+            | TerminatorKind::Return
+            | TerminatorKind::Unreachable
+            | TerminatorKind::GeneratorDrop
+            | TerminatorKind::Yield { .. }
+            | TerminatorKind::SwitchInt { .. }
+            | TerminatorKind::FalseEdge { .. }
+            | TerminatorKind::InlineAsm { .. } => None,
+            TerminatorKind::Call { cleanup: ref unwind, .. }
+            | TerminatorKind::Assert { cleanup: ref unwind, .. }
+            | TerminatorKind::DropAndReplace { ref unwind, .. }
+            | TerminatorKind::Drop { ref unwind, .. }
+            | TerminatorKind::FalseUnwind { ref unwind, .. } => Some(unwind),
+        }
+    }
+
+    pub fn unwind_mut(&mut self) -> Option<&mut Option<BasicBlock>> {
+        match *self {
+            TerminatorKind::Goto { .. }
+            | TerminatorKind::Resume
+            | TerminatorKind::Abort
+            | TerminatorKind::Return
+            | TerminatorKind::Unreachable
+            | TerminatorKind::GeneratorDrop
+            | TerminatorKind::Yield { .. }
+            | TerminatorKind::SwitchInt { .. }
+            | TerminatorKind::FalseEdge { .. }
+            | TerminatorKind::InlineAsm { .. } => None,
+            TerminatorKind::Call { cleanup: ref mut unwind, .. }
+            | TerminatorKind::Assert { cleanup: ref mut unwind, .. }
+            | TerminatorKind::DropAndReplace { ref mut unwind, .. }
+            | TerminatorKind::Drop { ref mut unwind, .. }
+            | TerminatorKind::FalseUnwind { ref mut unwind, .. } => Some(unwind),
+        }
+    }
+}
+
+impl<'tcx> Debug for TerminatorKind<'tcx> {
+    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
+        self.fmt_head(fmt)?;
+        let successor_count = self.successors().count();
+        let labels = self.fmt_successor_labels();
+        assert_eq!(successor_count, labels.len());
+
+        match successor_count {
+            0 => Ok(()),
+
+            1 => write!(fmt, " -> {:?}", self.successors().next().unwrap()),
+
+            _ => {
+                write!(fmt, " -> [")?;
+                for (i, target) in self.successors().enumerate() {
+                    if i > 0 {
+                        write!(fmt, ", ")?;
+                    }
+                    write!(fmt, "{}: {:?}", labels[i], target)?;
+                }
+                write!(fmt, "]")
+            }
+        }
+    }
+}
+
+impl<'tcx> TerminatorKind<'tcx> {
+    /// Writes the "head" part of the terminator; that is, its name and the data it uses to pick the
+    /// successor basic block, if any. The only information not included is the list of possible
+    /// successors, which may be rendered differently between the text and the graphviz format.
+    pub fn fmt_head<W: Write>(&self, fmt: &mut W) -> fmt::Result {
+        use self::TerminatorKind::*;
+        match self {
+            Goto { .. } => write!(fmt, "goto"),
+            SwitchInt { discr, .. } => write!(fmt, "switchInt({:?})", discr),
+            Return => write!(fmt, "return"),
+            GeneratorDrop => write!(fmt, "generator_drop"),
+            Resume => write!(fmt, "resume"),
+            Abort => write!(fmt, "abort"),
+            Yield { value, resume_arg, .. } => write!(fmt, "{:?} = yield({:?})", resume_arg, value),
+            Unreachable => write!(fmt, "unreachable"),
+            Drop { place, .. } => write!(fmt, "drop({:?})", place),
+            DropAndReplace { place, value, .. } => {
+                write!(fmt, "replace({:?} <- {:?})", place, value)
+            }
+            Call { func, args, destination, .. } => {
+                if let Some((destination, _)) = destination {
+                    write!(fmt, "{:?} = ", destination)?;
+                }
+                write!(fmt, "{:?}(", func)?;
+                for (index, arg) in args.iter().enumerate() {
+                    if index > 0 {
+                        write!(fmt, ", ")?;
+                    }
+                    write!(fmt, "{:?}", arg)?;
+                }
+                write!(fmt, ")")
+            }
+            Assert { cond, expected, msg, .. } => {
+                write!(fmt, "assert(")?;
+                if !expected {
+                    write!(fmt, "!")?;
+                }
+                write!(fmt, "{:?}, ", cond)?;
+                msg.fmt_assert_args(fmt)?;
+                write!(fmt, ")")
+            }
+            FalseEdge { .. } => write!(fmt, "falseEdge"),
+            FalseUnwind { .. } => write!(fmt, "falseUnwind"),
+            InlineAsm { template, ref operands, options, .. } => {
+                write!(fmt, "asm!(\"{}\"", InlineAsmTemplatePiece::to_string(template))?;
+                for op in operands {
+                    write!(fmt, ", ")?;
+                    let print_late = |&late| if late { "late" } else { "" };
+                    match op {
+                        InlineAsmOperand::In { reg, value } => {
+                            write!(fmt, "in({}) {:?}", reg, value)?;
+                        }
+                        InlineAsmOperand::Out { reg, late, place: Some(place) } => {
+                            write!(fmt, "{}out({}) {:?}", print_late(late), reg, place)?;
+                        }
+                        InlineAsmOperand::Out { reg, late, place: None } => {
+                            write!(fmt, "{}out({}) _", print_late(late), reg)?;
+                        }
+                        InlineAsmOperand::InOut {
+                            reg,
+                            late,
+                            in_value,
+                            out_place: Some(out_place),
+                        } => {
+                            write!(
+                                fmt,
+                                "in{}out({}) {:?} => {:?}",
+                                print_late(late),
+                                reg,
+                                in_value,
+                                out_place
+                            )?;
+                        }
+                        InlineAsmOperand::InOut { reg, late, in_value, out_place: None } => {
+                            write!(fmt, "in{}out({}) {:?} => _", print_late(late), reg, in_value)?;
+                        }
+                        InlineAsmOperand::Const { value } => {
+                            write!(fmt, "const {:?}", value)?;
+                        }
+                        InlineAsmOperand::SymFn { value } => {
+                            write!(fmt, "sym_fn {:?}", value)?;
+                        }
+                        InlineAsmOperand::SymStatic { def_id } => {
+                            write!(fmt, "sym_static {:?}", def_id)?;
+                        }
+                    }
+                }
+                write!(fmt, ", options({:?}))", options)
+            }
+        }
+    }
+
+    /// Returns the list of labels for the edges to the successor basic blocks.
+    pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> {
+        use self::TerminatorKind::*;
+        match *self {
+            Return | Resume | Abort | Unreachable | GeneratorDrop => vec![],
+            Goto { .. } => vec!["".into()],
+            SwitchInt { ref values, switch_ty, .. } => ty::tls::with(|tcx| {
+                let param_env = ty::ParamEnv::empty();
+                let switch_ty = tcx.lift(&switch_ty).unwrap();
+                let size = tcx.layout_of(param_env.and(switch_ty)).unwrap().size;
+                values
+                    .iter()
+                    .map(|&u| {
+                        ty::Const::from_scalar(tcx, Scalar::from_uint(u, size), switch_ty)
+                            .to_string()
+                            .into()
+                    })
+                    .chain(iter::once("otherwise".into()))
+                    .collect()
+            }),
+            Call { destination: Some(_), cleanup: Some(_), .. } => {
+                vec!["return".into(), "unwind".into()]
+            }
+            Call { destination: Some(_), cleanup: None, .. } => vec!["return".into()],
+            Call { destination: None, cleanup: Some(_), .. } => vec!["unwind".into()],
+            Call { destination: None, cleanup: None, .. } => vec![],
+            Yield { drop: Some(_), .. } => vec!["resume".into(), "drop".into()],
+            Yield { drop: None, .. } => vec!["resume".into()],
+            DropAndReplace { unwind: None, .. } | Drop { unwind: None, .. } => {
+                vec!["return".into()]
+            }
+            DropAndReplace { unwind: Some(_), .. } | Drop { unwind: Some(_), .. } => {
+                vec!["return".into(), "unwind".into()]
+            }
+            Assert { cleanup: None, .. } => vec!["".into()],
+            Assert { .. } => vec!["success".into(), "unwind".into()],
+            FalseEdge { .. } => vec!["real".into(), "imaginary".into()],
+            FalseUnwind { unwind: Some(_), .. } => vec!["real".into(), "cleanup".into()],
+            FalseUnwind { unwind: None, .. } => vec!["real".into()],
+            InlineAsm { destination: Some(_), .. } => vec!["".into()],
+            InlineAsm { destination: None, .. } => vec![],
+        }
+    }
+}
diff --git a/src/librustc_middle/ty/_match.rs b/src/librustc_middle/ty/_match.rs
index db9229ae3d214..4693a2f66fb4c 100644
--- a/src/librustc_middle/ty/_match.rs
+++ b/src/librustc_middle/ty/_match.rs
@@ -46,8 +46,8 @@ impl TypeRelation<'tcx> for Match<'tcx> {
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         _: ty::Variance,
-        a: &T,
-        b: &T,
+        a: T,
+        b: T,
     ) -> RelateResult<'tcx, T> {
         self.relate(a, b)
     }
@@ -112,8 +112,8 @@ impl TypeRelation<'tcx> for Match<'tcx> {
 
     fn binders<T>(
         &mut self,
-        a: &ty::Binder<T>,
-        b: &ty::Binder<T>,
+        a: ty::Binder<T>,
+        b: ty::Binder<T>,
     ) -> RelateResult<'tcx, ty::Binder<T>>
     where
         T: Relate<'tcx>,
diff --git a/src/librustc_middle/ty/error.rs b/src/librustc_middle/ty/error.rs
index 6113359ca93a7..30ff5a2d9ebdf 100644
--- a/src/librustc_middle/ty/error.rs
+++ b/src/librustc_middle/ty/error.rs
@@ -57,7 +57,6 @@ pub enum TypeError<'tcx> {
     /// type).
     CyclicTy(Ty<'tcx>),
     ProjectionMismatched(ExpectedFound<DefId>),
-    ProjectionBoundsLength(ExpectedFound<usize>),
     ExistentialMismatch(ExpectedFound<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>),
     ObjectUnsafeCoercion(DefId),
     ConstMismatch(ExpectedFound<&'tcx ty::Const<'tcx>>),
@@ -174,13 +173,6 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
                     tcx.def_path_str(values.found)
                 )
             }),
-            ProjectionBoundsLength(ref values) => write!(
-                f,
-                "expected {} associated type binding{}, found {}",
-                values.expected,
-                pluralize!(values.expected),
-                values.found
-            ),
             ExistentialMismatch(ref values) => report_maybe_different(
                 f,
                 &format!("trait `{}`", values.expected),
@@ -216,7 +208,6 @@ impl<'tcx> TypeError<'tcx> {
             | RegionsPlaceholderMismatch
             | Traits(_)
             | ProjectionMismatched(_)
-            | ProjectionBoundsLength(_)
             | ExistentialMismatch(_)
             | ConstMismatch(_)
             | IntrinsicCast
diff --git a/src/librustc_middle/ty/flags.rs b/src/librustc_middle/ty/flags.rs
index c782eee938721..0e86fcf53b247 100644
--- a/src/librustc_middle/ty/flags.rs
+++ b/src/librustc_middle/ty/flags.rs
@@ -88,13 +88,13 @@ impl FlagComputation {
                 self.add_substs(substs);
             }
 
-            &ty::GeneratorWitness(ref ts) => {
+            &ty::GeneratorWitness(ts) => {
                 let mut computation = FlagComputation::new();
-                computation.add_tys(&ts.skip_binder()[..]);
+                computation.add_tys(ts.skip_binder());
                 self.add_bound_computation(computation);
             }
 
-            &ty::Closure(_, ref substs) => {
+            &ty::Closure(_, substs) => {
                 self.add_substs(substs);
             }
 
@@ -122,7 +122,7 @@ impl FlagComputation {
                 self.add_substs(substs);
             }
 
-            &ty::Projection(ref data) => {
+            &ty::Projection(data) => {
                 self.add_flags(TypeFlags::HAS_TY_PROJECTION);
                 self.add_projection_ty(data);
             }
@@ -211,7 +211,7 @@ impl FlagComputation {
 
                 self.add_bound_computation(computation);
             }
-            ty::PredicateKind::Projection(projection) => {
+            &ty::PredicateKind::Projection(projection) => {
                 let mut computation = FlagComputation::new();
                 let ty::ProjectionPredicate { projection_ty, ty } = projection.skip_binder();
                 computation.add_projection_ty(projection_ty);
@@ -298,7 +298,7 @@ impl FlagComputation {
         self.add_ty(projection.ty);
     }
 
-    fn add_projection_ty(&mut self, projection_ty: &ty::ProjectionTy<'_>) {
+    fn add_projection_ty(&mut self, projection_ty: ty::ProjectionTy<'_>) {
         self.add_substs(projection_ty.substs);
     }
 
diff --git a/src/librustc_middle/ty/fold.rs b/src/librustc_middle/ty/fold.rs
index 2d25c7c6ac983..492f8ce9ef1a9 100644
--- a/src/librustc_middle/ty/fold.rs
+++ b/src/librustc_middle/ty/fold.rs
@@ -336,7 +336,7 @@ impl<'tcx> TyCtxt<'tcx> {
         {
             fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> bool {
                 self.outer_index.shift_in(1);
-                let result = t.skip_binder().visit_with(self);
+                let result = t.as_ref().skip_binder().visit_with(self);
                 self.outer_index.shift_out(1);
                 result
             }
@@ -558,7 +558,7 @@ impl<'tcx> TyCtxt<'tcx> {
         let fld_c = |bound_ct, ty| {
             self.mk_const(ty::Const { val: ty::ConstKind::Bound(ty::INNERMOST, bound_ct), ty })
         };
-        self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t, fld_c)
+        self.replace_escaping_bound_vars(value.as_ref().skip_binder(), fld_r, fld_t, fld_c)
     }
 
     /// Replaces all escaping bound vars. The `fld_r` closure replaces escaping
@@ -617,7 +617,7 @@ impl<'tcx> TyCtxt<'tcx> {
         H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx>,
         T: TypeFoldable<'tcx>,
     {
-        self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t, fld_c)
+        self.replace_escaping_bound_vars(value.as_ref().skip_binder(), fld_r, fld_t, fld_c)
     }
 
     /// Replaces any late-bound regions bound in `value` with
@@ -673,7 +673,7 @@ impl<'tcx> TyCtxt<'tcx> {
         T: TypeFoldable<'tcx>,
     {
         let mut collector = LateBoundRegionsCollector::new(just_constraint);
-        let result = value.skip_binder().visit_with(&mut collector);
+        let result = value.as_ref().skip_binder().visit_with(&mut collector);
         assert!(!result); // should never have stopped early
         collector.regions
     }
diff --git a/src/librustc_middle/ty/layout.rs b/src/librustc_middle/ty/layout.rs
index e4cc96dd83bfb..39b8566e7a873 100644
--- a/src/librustc_middle/ty/layout.rs
+++ b/src/librustc_middle/ty/layout.rs
@@ -2303,7 +2303,7 @@ impl<'tcx> ty::Instance<'tcx> {
 
                 let env_ty = tcx.closure_env_ty(def_id, substs).unwrap();
                 sig.map_bound(|sig| tcx.mk_fn_sig(
-                    iter::once(*env_ty.skip_binder()).chain(sig.inputs().iter().cloned()),
+                    iter::once(env_ty.skip_binder()).chain(sig.inputs().iter().cloned()),
                     sig.output(),
                     sig.c_variadic,
                     sig.unsafety,
diff --git a/src/librustc_middle/ty/print/pretty.rs b/src/librustc_middle/ty/print/pretty.rs
index 061214249713d..9fa1260f64d74 100644
--- a/src/librustc_middle/ty/print/pretty.rs
+++ b/src/librustc_middle/ty/print/pretty.rs
@@ -189,7 +189,7 @@ pub trait PrettyPrinter<'tcx>:
     where
         T: Print<'tcx, Self, Output = Self, Error = Self::Error> + TypeFoldable<'tcx>,
     {
-        value.skip_binder().print(self)
+        value.as_ref().skip_binder().print(self)
     }
 
     /// Prints comma-separated elements.
diff --git a/src/librustc_middle/ty/relate.rs b/src/librustc_middle/ty/relate.rs
index e9a8b9095bf72..cee04ce8c6a83 100644
--- a/src/librustc_middle/ty/relate.rs
+++ b/src/librustc_middle/ty/relate.rs
@@ -13,7 +13,6 @@ use rustc_hir::def_id::DefId;
 use rustc_span::DUMMY_SP;
 use rustc_target::spec::abi;
 use std::iter;
-use std::rc::Rc;
 
 pub type RelateResult<'tcx, T> = Result<T, TypeError<'tcx>>;
 
@@ -42,7 +41,7 @@ pub trait TypeRelation<'tcx>: Sized {
     }
 
     /// Generic relation routine suitable for most anything.
-    fn relate<T: Relate<'tcx>>(&mut self, a: &T, b: &T) -> RelateResult<'tcx, T> {
+    fn relate<T: Relate<'tcx>>(&mut self, a: T, b: T) -> RelateResult<'tcx, T> {
         Relate::relate(self, a, b)
     }
 
@@ -68,8 +67,8 @@ pub trait TypeRelation<'tcx>: Sized {
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         variance: ty::Variance,
-        a: &T,
-        b: &T,
+        a: T,
+        b: T,
     ) -> RelateResult<'tcx, T>;
 
     // Overridable relations. You shouldn't typically call these
@@ -94,18 +93,18 @@ pub trait TypeRelation<'tcx>: Sized {
 
     fn binders<T>(
         &mut self,
-        a: &ty::Binder<T>,
-        b: &ty::Binder<T>,
+        a: ty::Binder<T>,
+        b: ty::Binder<T>,
     ) -> RelateResult<'tcx, ty::Binder<T>>
     where
         T: Relate<'tcx>;
 }
 
-pub trait Relate<'tcx>: TypeFoldable<'tcx> {
+pub trait Relate<'tcx>: TypeFoldable<'tcx> + Copy {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
-        a: &Self,
-        b: &Self,
+        a: Self,
+        b: Self,
     ) -> RelateResult<'tcx, Self>;
 }
 
@@ -115,8 +114,8 @@ pub trait Relate<'tcx>: TypeFoldable<'tcx> {
 impl<'tcx> Relate<'tcx> for ty::TypeAndMut<'tcx> {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
-        a: &ty::TypeAndMut<'tcx>,
-        b: &ty::TypeAndMut<'tcx>,
+        a: ty::TypeAndMut<'tcx>,
+        b: ty::TypeAndMut<'tcx>,
     ) -> RelateResult<'tcx, ty::TypeAndMut<'tcx>> {
         debug!("{}.mts({:?}, {:?})", relation.tag(), a, b);
         if a.mutbl != b.mutbl {
@@ -127,7 +126,7 @@ impl<'tcx> Relate<'tcx> for ty::TypeAndMut<'tcx> {
                 ast::Mutability::Not => ty::Covariant,
                 ast::Mutability::Mut => ty::Invariant,
             };
-            let ty = relation.relate_with_variance(variance, &a.ty, &b.ty)?;
+            let ty = relation.relate_with_variance(variance, a.ty, b.ty)?;
             Ok(ty::TypeAndMut { ty, mutbl })
         }
     }
@@ -143,7 +142,7 @@ pub fn relate_substs<R: TypeRelation<'tcx>>(
 
     let params = a_subst.iter().zip(b_subst).enumerate().map(|(i, (a, b))| {
         let variance = variances.map_or(ty::Invariant, |v| v[i]);
-        relation.relate_with_variance(variance, &a, &b)
+        relation.relate_with_variance(variance, a, b)
     });
 
     Ok(tcx.mk_substs(params)?)
@@ -152,8 +151,8 @@ pub fn relate_substs<R: TypeRelation<'tcx>>(
 impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
-        a: &ty::FnSig<'tcx>,
-        b: &ty::FnSig<'tcx>,
+        a: ty::FnSig<'tcx>,
+        b: ty::FnSig<'tcx>,
     ) -> RelateResult<'tcx, ty::FnSig<'tcx>> {
         let tcx = relation.tcx();
 
@@ -164,8 +163,8 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
                 &b.c_variadic,
             )));
         }
-        let unsafety = relation.relate(&a.unsafety, &b.unsafety)?;
-        let abi = relation.relate(&a.abi, &b.abi)?;
+        let unsafety = relation.relate(a.unsafety, b.unsafety)?;
+        let abi = relation.relate(a.abi, b.abi)?;
 
         if a.inputs().len() != b.inputs().len() {
             return Err(TypeError::ArgCount);
@@ -180,9 +179,9 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
             .chain(iter::once(((a.output(), b.output()), true)))
             .map(|((a, b), is_output)| {
                 if is_output {
-                    relation.relate(&a, &b)
+                    relation.relate(a, b)
                 } else {
-                    relation.relate_with_variance(ty::Contravariant, &a, &b)
+                    relation.relate_with_variance(ty::Contravariant, a, b)
                 }
             });
         Ok(ty::FnSig {
@@ -197,13 +196,13 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
 impl<'tcx> Relate<'tcx> for ast::Unsafety {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
-        a: &ast::Unsafety,
-        b: &ast::Unsafety,
+        a: ast::Unsafety,
+        b: ast::Unsafety,
     ) -> RelateResult<'tcx, ast::Unsafety> {
         if a != b {
-            Err(TypeError::UnsafetyMismatch(expected_found(relation, a, b)))
+            Err(TypeError::UnsafetyMismatch(expected_found(relation, &a, &b)))
         } else {
-            Ok(*a)
+            Ok(a)
         }
     }
 }
@@ -211,18 +210,18 @@ impl<'tcx> Relate<'tcx> for ast::Unsafety {
 impl<'tcx> Relate<'tcx> for abi::Abi {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
-        a: &abi::Abi,
-        b: &abi::Abi,
+        a: abi::Abi,
+        b: abi::Abi,
     ) -> RelateResult<'tcx, abi::Abi> {
-        if a == b { Ok(*a) } else { Err(TypeError::AbiMismatch(expected_found(relation, a, b))) }
+        if a == b { Ok(a) } else { Err(TypeError::AbiMismatch(expected_found(relation, &a, &b))) }
     }
 }
 
 impl<'tcx> Relate<'tcx> for ty::ProjectionTy<'tcx> {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
-        a: &ty::ProjectionTy<'tcx>,
-        b: &ty::ProjectionTy<'tcx>,
+        a: ty::ProjectionTy<'tcx>,
+        b: ty::ProjectionTy<'tcx>,
     ) -> RelateResult<'tcx, ty::ProjectionTy<'tcx>> {
         if a.item_def_id != b.item_def_id {
             Err(TypeError::ProjectionMismatched(expected_found(
@@ -231,7 +230,7 @@ impl<'tcx> Relate<'tcx> for ty::ProjectionTy<'tcx> {
                 &b.item_def_id,
             )))
         } else {
-            let substs = relation.relate(&a.substs, &b.substs)?;
+            let substs = relation.relate(a.substs, b.substs)?;
             Ok(ty::ProjectionTy { item_def_id: a.item_def_id, substs: &substs })
         }
     }
@@ -240,8 +239,8 @@ impl<'tcx> Relate<'tcx> for ty::ProjectionTy<'tcx> {
 impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'tcx> {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
-        a: &ty::ExistentialProjection<'tcx>,
-        b: &ty::ExistentialProjection<'tcx>,
+        a: ty::ExistentialProjection<'tcx>,
+        b: ty::ExistentialProjection<'tcx>,
     ) -> RelateResult<'tcx, ty::ExistentialProjection<'tcx>> {
         if a.item_def_id != b.item_def_id {
             Err(TypeError::ProjectionMismatched(expected_found(
@@ -250,37 +249,18 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'tcx> {
                 &b.item_def_id,
             )))
         } else {
-            let ty = relation.relate_with_variance(ty::Invariant, &a.ty, &b.ty)?;
-            let substs = relation.relate_with_variance(ty::Invariant, &a.substs, &b.substs)?;
+            let ty = relation.relate_with_variance(ty::Invariant, a.ty, b.ty)?;
+            let substs = relation.relate_with_variance(ty::Invariant, a.substs, b.substs)?;
             Ok(ty::ExistentialProjection { item_def_id: a.item_def_id, substs, ty })
         }
     }
 }
 
-impl<'tcx> Relate<'tcx> for Vec<ty::PolyExistentialProjection<'tcx>> {
-    fn relate<R: TypeRelation<'tcx>>(
-        relation: &mut R,
-        a: &Vec<ty::PolyExistentialProjection<'tcx>>,
-        b: &Vec<ty::PolyExistentialProjection<'tcx>>,
-    ) -> RelateResult<'tcx, Vec<ty::PolyExistentialProjection<'tcx>>> {
-        // To be compatible, `a` and `b` must be for precisely the
-        // same set of traits and item names. We always require that
-        // projection bounds lists are sorted by trait-def-id and item-name,
-        // so we can just iterate through the lists pairwise, so long as they are the
-        // same length.
-        if a.len() != b.len() {
-            Err(TypeError::ProjectionBoundsLength(expected_found(relation, &a.len(), &b.len())))
-        } else {
-            a.iter().zip(b).map(|(a, b)| relation.relate(a, b)).collect()
-        }
-    }
-}
-
 impl<'tcx> Relate<'tcx> for ty::TraitRef<'tcx> {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
-        a: &ty::TraitRef<'tcx>,
-        b: &ty::TraitRef<'tcx>,
+        a: ty::TraitRef<'tcx>,
+        b: ty::TraitRef<'tcx>,
     ) -> RelateResult<'tcx, ty::TraitRef<'tcx>> {
         // Different traits cannot be related.
         if a.def_id != b.def_id {
@@ -295,8 +275,8 @@ impl<'tcx> Relate<'tcx> for ty::TraitRef<'tcx> {
 impl<'tcx> Relate<'tcx> for ty::ExistentialTraitRef<'tcx> {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
-        a: &ty::ExistentialTraitRef<'tcx>,
-        b: &ty::ExistentialTraitRef<'tcx>,
+        a: ty::ExistentialTraitRef<'tcx>,
+        b: ty::ExistentialTraitRef<'tcx>,
     ) -> RelateResult<'tcx, ty::ExistentialTraitRef<'tcx>> {
         // Different traits cannot be related.
         if a.def_id != b.def_id {
@@ -308,18 +288,18 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialTraitRef<'tcx> {
     }
 }
 
-#[derive(Debug, Clone, TypeFoldable)]
+#[derive(Copy, Debug, Clone, TypeFoldable)]
 struct GeneratorWitness<'tcx>(&'tcx ty::List<Ty<'tcx>>);
 
 impl<'tcx> Relate<'tcx> for GeneratorWitness<'tcx> {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
-        a: &GeneratorWitness<'tcx>,
-        b: &GeneratorWitness<'tcx>,
+        a: GeneratorWitness<'tcx>,
+        b: GeneratorWitness<'tcx>,
     ) -> RelateResult<'tcx, GeneratorWitness<'tcx>> {
         assert_eq!(a.0.len(), b.0.len());
         let tcx = relation.tcx();
-        let types = tcx.mk_type_list(a.0.iter().zip(b.0).map(|(a, b)| relation.relate(&a, &b)))?;
+        let types = tcx.mk_type_list(a.0.iter().zip(b.0).map(|(a, b)| relation.relate(a, b)))?;
         Ok(GeneratorWitness(types))
     }
 }
@@ -327,8 +307,8 @@ impl<'tcx> Relate<'tcx> for GeneratorWitness<'tcx> {
 impl<'tcx> Relate<'tcx> for Ty<'tcx> {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
-        a: &Ty<'tcx>,
-        b: &Ty<'tcx>,
+        a: Ty<'tcx>,
+        b: Ty<'tcx>,
     ) -> RelateResult<'tcx, Ty<'tcx>> {
         relation.tys(a, b)
     }
@@ -379,7 +359,7 @@ pub fn super_relate_tys<R: TypeRelation<'tcx>>(
 
         (&ty::Foreign(a_id), &ty::Foreign(b_id)) if a_id == b_id => Ok(tcx.mk_foreign(a_id)),
 
-        (&ty::Dynamic(ref a_obj, ref a_region), &ty::Dynamic(ref b_obj, ref b_region)) => {
+        (&ty::Dynamic(a_obj, a_region), &ty::Dynamic(b_obj, b_region)) => {
             let region_bound = relation.with_cause(Cause::ExistentialRegionBound, |relation| {
                 relation.relate_with_variance(ty::Contravariant, a_region, b_region)
             })?;
@@ -392,7 +372,7 @@ pub fn super_relate_tys<R: TypeRelation<'tcx>>(
             // All Generator types with the same id represent
             // the (anonymous) type of the same generator expression. So
             // all of their regions should be equated.
-            let substs = relation.relate(&a_substs, &b_substs)?;
+            let substs = relation.relate(a_substs, b_substs)?;
             Ok(tcx.mk_generator(a_id, substs, movability))
         }
 
@@ -402,7 +382,7 @@ pub fn super_relate_tys<R: TypeRelation<'tcx>>(
             let a_types = a_types.map_bound(GeneratorWitness);
             let b_types = b_types.map_bound(GeneratorWitness);
             // Then remove the GeneratorWitness for the result
-            let types = relation.relate(&a_types, &b_types)?.map_bound(|witness| witness.0);
+            let types = relation.relate(a_types, b_types)?.map_bound(|witness| witness.0);
             Ok(tcx.mk_generator_witness(types))
         }
 
@@ -410,26 +390,26 @@ pub fn super_relate_tys<R: TypeRelation<'tcx>>(
             // All Closure types with the same id represent
             // the (anonymous) type of the same closure expression. So
             // all of their regions should be equated.
-            let substs = relation.relate(&a_substs, &b_substs)?;
+            let substs = relation.relate(a_substs, b_substs)?;
             Ok(tcx.mk_closure(a_id, &substs))
         }
 
-        (&ty::RawPtr(ref a_mt), &ty::RawPtr(ref b_mt)) => {
+        (&ty::RawPtr(a_mt), &ty::RawPtr(b_mt)) => {
             let mt = relation.relate(a_mt, b_mt)?;
             Ok(tcx.mk_ptr(mt))
         }
 
         (&ty::Ref(a_r, a_ty, a_mutbl), &ty::Ref(b_r, b_ty, b_mutbl)) => {
-            let r = relation.relate_with_variance(ty::Contravariant, &a_r, &b_r)?;
+            let r = relation.relate_with_variance(ty::Contravariant, a_r, b_r)?;
             let a_mt = ty::TypeAndMut { ty: a_ty, mutbl: a_mutbl };
             let b_mt = ty::TypeAndMut { ty: b_ty, mutbl: b_mutbl };
-            let mt = relation.relate(&a_mt, &b_mt)?;
+            let mt = relation.relate(a_mt, b_mt)?;
             Ok(tcx.mk_ref(r, mt))
         }
 
         (&ty::Array(a_t, sz_a), &ty::Array(b_t, sz_b)) => {
-            let t = relation.relate(&a_t, &b_t)?;
-            match relation.relate(&sz_a, &sz_b) {
+            let t = relation.relate(a_t, b_t)?;
+            match relation.relate(sz_a, sz_b) {
                 Ok(sz) => Ok(tcx.mk_ty(ty::Array(t, sz))),
                 // FIXME(#72219) Implement improved diagnostics for mismatched array
                 // length?
@@ -450,16 +430,14 @@ pub fn super_relate_tys<R: TypeRelation<'tcx>>(
         }
 
         (&ty::Slice(a_t), &ty::Slice(b_t)) => {
-            let t = relation.relate(&a_t, &b_t)?;
+            let t = relation.relate(a_t, b_t)?;
             Ok(tcx.mk_slice(t))
         }
 
         (&ty::Tuple(as_), &ty::Tuple(bs)) => {
             if as_.len() == bs.len() {
                 Ok(tcx.mk_tup(
-                    as_.iter()
-                        .zip(bs)
-                        .map(|(a, b)| relation.relate(&a.expect_ty(), &b.expect_ty())),
+                    as_.iter().zip(bs).map(|(a, b)| relation.relate(a.expect_ty(), b.expect_ty())),
                 )?)
             } else if !(as_.is_empty() || bs.is_empty()) {
                 Err(TypeError::TupleSize(expected_found(relation, &as_.len(), &bs.len())))
@@ -476,12 +454,12 @@ pub fn super_relate_tys<R: TypeRelation<'tcx>>(
         }
 
         (&ty::FnPtr(a_fty), &ty::FnPtr(b_fty)) => {
-            let fty = relation.relate(&a_fty, &b_fty)?;
+            let fty = relation.relate(a_fty, b_fty)?;
             Ok(tcx.mk_fn_ptr(fty))
         }
 
         // these two are already handled downstream in case of lazy normalization
-        (ty::Projection(a_data), ty::Projection(b_data)) => {
+        (&ty::Projection(a_data), &ty::Projection(b_data)) => {
             let projection_ty = relation.relate(a_data, b_data)?;
             Ok(tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs))
         }
@@ -603,8 +581,8 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
             ty::ConstKind::Unevaluated(b_def_id, b_substs, b_promoted),
         ) if a_def_id == b_def_id && a_promoted == b_promoted => {
             let substs =
-                relation.relate_with_variance(ty::Variance::Invariant, &a_substs, &b_substs)?;
-            Ok(ty::ConstKind::Unevaluated(a_def_id, &substs, a_promoted))
+                relation.relate_with_variance(ty::Variance::Invariant, a_substs, b_substs)?;
+            Ok(ty::ConstKind::Unevaluated(a_def_id, substs, a_promoted))
         }
         _ => Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))),
     };
@@ -614,8 +592,8 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
 impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::ExistentialPredicate<'tcx>> {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
-        a: &Self,
-        b: &Self,
+        a: Self,
+        b: Self,
     ) -> RelateResult<'tcx, Self> {
         let tcx = relation.tcx();
 
@@ -629,16 +607,16 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::ExistentialPredicate<'tcx>> {
         b_v.sort_by(|a, b| a.stable_cmp(tcx, b));
         b_v.dedup();
         if a_v.len() != b_v.len() {
-            return Err(TypeError::ExistentialMismatch(expected_found(relation, a, b)));
+            return Err(TypeError::ExistentialMismatch(expected_found(relation, &a, &b)));
         }
 
         let v = a_v.into_iter().zip(b_v.into_iter()).map(|(ep_a, ep_b)| {
             use crate::ty::ExistentialPredicate::*;
             match (ep_a, ep_b) {
-                (Trait(ref a), Trait(ref b)) => Ok(Trait(relation.relate(a, b)?)),
-                (Projection(ref a), Projection(ref b)) => Ok(Projection(relation.relate(a, b)?)),
-                (AutoTrait(ref a), AutoTrait(ref b)) if a == b => Ok(AutoTrait(*a)),
-                _ => Err(TypeError::ExistentialMismatch(expected_found(relation, a, b))),
+                (Trait(a), Trait(b)) => Ok(Trait(relation.relate(a, b)?)),
+                (Projection(a), Projection(b)) => Ok(Projection(relation.relate(a, b)?)),
+                (AutoTrait(a), AutoTrait(b)) if a == b => Ok(AutoTrait(a)),
+                _ => Err(TypeError::ExistentialMismatch(expected_found(relation, &a, &b))),
             }
         });
         Ok(tcx.mk_existential_predicates(v)?)
@@ -648,8 +626,8 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::ExistentialPredicate<'tcx>> {
 impl<'tcx> Relate<'tcx> for ty::ClosureSubsts<'tcx> {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
-        a: &ty::ClosureSubsts<'tcx>,
-        b: &ty::ClosureSubsts<'tcx>,
+        a: ty::ClosureSubsts<'tcx>,
+        b: ty::ClosureSubsts<'tcx>,
     ) -> RelateResult<'tcx, ty::ClosureSubsts<'tcx>> {
         let substs = relate_substs(relation, None, a.substs, b.substs)?;
         Ok(ty::ClosureSubsts { substs })
@@ -659,8 +637,8 @@ impl<'tcx> Relate<'tcx> for ty::ClosureSubsts<'tcx> {
 impl<'tcx> Relate<'tcx> for ty::GeneratorSubsts<'tcx> {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
-        a: &ty::GeneratorSubsts<'tcx>,
-        b: &ty::GeneratorSubsts<'tcx>,
+        a: ty::GeneratorSubsts<'tcx>,
+        b: ty::GeneratorSubsts<'tcx>,
     ) -> RelateResult<'tcx, ty::GeneratorSubsts<'tcx>> {
         let substs = relate_substs(relation, None, a.substs, b.substs)?;
         Ok(ty::GeneratorSubsts { substs })
@@ -670,8 +648,8 @@ impl<'tcx> Relate<'tcx> for ty::GeneratorSubsts<'tcx> {
 impl<'tcx> Relate<'tcx> for SubstsRef<'tcx> {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
-        a: &SubstsRef<'tcx>,
-        b: &SubstsRef<'tcx>,
+        a: SubstsRef<'tcx>,
+        b: SubstsRef<'tcx>,
     ) -> RelateResult<'tcx, SubstsRef<'tcx>> {
         relate_substs(relation, None, a, b)
     }
@@ -680,72 +658,48 @@ impl<'tcx> Relate<'tcx> for SubstsRef<'tcx> {
 impl<'tcx> Relate<'tcx> for ty::Region<'tcx> {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
-        a: &ty::Region<'tcx>,
-        b: &ty::Region<'tcx>,
+        a: ty::Region<'tcx>,
+        b: ty::Region<'tcx>,
     ) -> RelateResult<'tcx, ty::Region<'tcx>> {
-        relation.regions(*a, *b)
+        relation.regions(a, b)
     }
 }
 
 impl<'tcx> Relate<'tcx> for &'tcx ty::Const<'tcx> {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
-        a: &&'tcx ty::Const<'tcx>,
-        b: &&'tcx ty::Const<'tcx>,
+        a: &'tcx ty::Const<'tcx>,
+        b: &'tcx ty::Const<'tcx>,
     ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
-        relation.consts(*a, *b)
+        relation.consts(a, b)
     }
 }
 
 impl<'tcx, T: Relate<'tcx>> Relate<'tcx> for ty::Binder<T> {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
-        a: &ty::Binder<T>,
-        b: &ty::Binder<T>,
+        a: ty::Binder<T>,
+        b: ty::Binder<T>,
     ) -> RelateResult<'tcx, ty::Binder<T>> {
         relation.binders(a, b)
     }
 }
 
-impl<'tcx, T: Relate<'tcx>> Relate<'tcx> for Rc<T> {
-    fn relate<R: TypeRelation<'tcx>>(
-        relation: &mut R,
-        a: &Rc<T>,
-        b: &Rc<T>,
-    ) -> RelateResult<'tcx, Rc<T>> {
-        let a: &T = a;
-        let b: &T = b;
-        Ok(Rc::new(relation.relate(a, b)?))
-    }
-}
-
-impl<'tcx, T: Relate<'tcx>> Relate<'tcx> for Box<T> {
-    fn relate<R: TypeRelation<'tcx>>(
-        relation: &mut R,
-        a: &Box<T>,
-        b: &Box<T>,
-    ) -> RelateResult<'tcx, Box<T>> {
-        let a: &T = a;
-        let b: &T = b;
-        Ok(Box::new(relation.relate(a, b)?))
-    }
-}
-
 impl<'tcx> Relate<'tcx> for GenericArg<'tcx> {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
-        a: &GenericArg<'tcx>,
-        b: &GenericArg<'tcx>,
+        a: GenericArg<'tcx>,
+        b: GenericArg<'tcx>,
     ) -> RelateResult<'tcx, GenericArg<'tcx>> {
         match (a.unpack(), b.unpack()) {
             (GenericArgKind::Lifetime(a_lt), GenericArgKind::Lifetime(b_lt)) => {
-                Ok(relation.relate(&a_lt, &b_lt)?.into())
+                Ok(relation.relate(a_lt, b_lt)?.into())
             }
             (GenericArgKind::Type(a_ty), GenericArgKind::Type(b_ty)) => {
-                Ok(relation.relate(&a_ty, &b_ty)?.into())
+                Ok(relation.relate(a_ty, b_ty)?.into())
             }
             (GenericArgKind::Const(a_ct), GenericArgKind::Const(b_ct)) => {
-                Ok(relation.relate(&a_ct, &b_ct)?.into())
+                Ok(relation.relate(a_ct, b_ct)?.into())
             }
             (GenericArgKind::Lifetime(unpacked), x) => {
                 bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x)
@@ -763,22 +717,22 @@ impl<'tcx> Relate<'tcx> for GenericArg<'tcx> {
 impl<'tcx> Relate<'tcx> for ty::TraitPredicate<'tcx> {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
-        a: &ty::TraitPredicate<'tcx>,
-        b: &ty::TraitPredicate<'tcx>,
+        a: ty::TraitPredicate<'tcx>,
+        b: ty::TraitPredicate<'tcx>,
     ) -> RelateResult<'tcx, ty::TraitPredicate<'tcx>> {
-        Ok(ty::TraitPredicate { trait_ref: relation.relate(&a.trait_ref, &b.trait_ref)? })
+        Ok(ty::TraitPredicate { trait_ref: relation.relate(a.trait_ref, b.trait_ref)? })
     }
 }
 
 impl<'tcx> Relate<'tcx> for ty::ProjectionPredicate<'tcx> {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
-        a: &ty::ProjectionPredicate<'tcx>,
-        b: &ty::ProjectionPredicate<'tcx>,
+        a: ty::ProjectionPredicate<'tcx>,
+        b: ty::ProjectionPredicate<'tcx>,
     ) -> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>> {
         Ok(ty::ProjectionPredicate {
-            projection_ty: relation.relate(&a.projection_ty, &b.projection_ty)?,
-            ty: relation.relate(&a.ty, &b.ty)?,
+            projection_ty: relation.relate(a.projection_ty, b.projection_ty)?,
+            ty: relation.relate(a.ty, b.ty)?,
         })
     }
 }
diff --git a/src/librustc_middle/ty/structural_impls.rs b/src/librustc_middle/ty/structural_impls.rs
index f736037b5c15a..1d3607fe32ffc 100644
--- a/src/librustc_middle/ty/structural_impls.rs
+++ b/src/librustc_middle/ty/structural_impls.rs
@@ -514,7 +514,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::PredicateKind<'a> {
 impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder<T> {
     type Lifted = ty::Binder<T::Lifted>;
     fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(self.skip_binder()).map(ty::Binder::bind)
+        tcx.lift(self.as_ref().skip_binder()).map(ty::Binder::bind)
     }
 }
 
@@ -655,7 +655,6 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
             VariadicMismatch(x) => VariadicMismatch(x),
             CyclicTy(t) => return tcx.lift(&t).map(|t| CyclicTy(t)),
             ProjectionMismatched(x) => ProjectionMismatched(x),
-            ProjectionBoundsLength(x) => ProjectionBoundsLength(x),
             Sorts(ref x) => return tcx.lift(x).map(Sorts),
             ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch),
             ConstMismatch(ref x) => return tcx.lift(x).map(ConstMismatch),
@@ -798,7 +797,7 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> {
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.skip_binder().visit_with(visitor)
+        self.as_ref().skip_binder().visit_with(visitor)
     }
 
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs
index 8f86d2ef522d3..c7683cefd82f6 100644
--- a/src/librustc_middle/ty/sty.rs
+++ b/src/librustc_middle/ty/sty.rs
@@ -615,7 +615,7 @@ impl<'tcx> ExistentialPredicate<'tcx> {
 impl<'tcx> Binder<ExistentialPredicate<'tcx>> {
     pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Predicate<'tcx> {
         use crate::ty::ToPredicate;
-        match *self.skip_binder() {
+        match self.skip_binder() {
             ExistentialPredicate::Trait(tr) => {
                 Binder(tr).with_self_ty(tcx, self_ty).without_const().to_predicate(tcx)
             }
@@ -776,7 +776,7 @@ impl<'tcx> PolyTraitRef<'tcx> {
 
     pub fn to_poly_trait_predicate(&self) -> ty::PolyTraitPredicate<'tcx> {
         // Note that we preserve binding levels
-        Binder(ty::TraitPredicate { trait_ref: *self.skip_binder() })
+        Binder(ty::TraitPredicate { trait_ref: self.skip_binder() })
     }
 }
 
@@ -880,8 +880,8 @@ impl<T> Binder<T> {
     /// - extracting the `DefId` from a PolyTraitRef;
     /// - comparing the self type of a PolyTraitRef to see if it is equal to
     ///   a type parameter `X`, since the type `X` does not reference any regions
-    pub fn skip_binder(&self) -> &T {
-        &self.0
+    pub fn skip_binder(self) -> T {
+        self.0
     }
 
     pub fn as_ref(&self) -> Binder<&T> {
@@ -916,11 +916,7 @@ impl<T> Binder<T> {
     where
         T: TypeFoldable<'tcx>,
     {
-        if self.skip_binder().has_escaping_bound_vars() {
-            None
-        } else {
-            Some(self.skip_binder().clone())
-        }
+        if self.0.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) }
     }
 
     /// Given two things that have the same binder level,
@@ -997,7 +993,7 @@ impl<'tcx> ProjectionTy<'tcx> {
     }
 }
 
-#[derive(Clone, Debug, TypeFoldable)]
+#[derive(Copy, Clone, Debug, TypeFoldable)]
 pub struct GenSig<'tcx> {
     pub resume_ty: Ty<'tcx>,
     pub yield_ty: Ty<'tcx>,
diff --git a/src/librustc_middle/ty/walk.rs b/src/librustc_middle/ty/walk.rs
index 633d4fda8a46d..82c649b8f543b 100644
--- a/src/librustc_middle/ty/walk.rs
+++ b/src/librustc_middle/ty/walk.rs
@@ -133,7 +133,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
             ty::Dynamic(obj, lt) => {
                 stack.push(lt.into());
                 stack.extend(obj.iter().rev().flat_map(|predicate| {
-                    let (substs, opt_ty) = match *predicate.skip_binder() {
+                    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(_) =>
diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
index e85f69554d0c8..17846055f6c96 100644
--- a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
@@ -1923,7 +1923,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
                 // We use a mix of the HIR and the Ty types to get information
                 // as the HIR doesn't have full types for closure arguments.
-                let return_ty = *sig.output().skip_binder();
+                let return_ty = sig.output().skip_binder();
                 let mut return_span = fn_decl.output.span();
                 if let hir::FnRetTy::Return(ty) = &fn_decl.output {
                     if let hir::TyKind::Rptr(lifetime, _) = ty.kind {
@@ -1965,7 +1965,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 let argument_ty = sig.inputs().skip_binder().first()?;
 
                 let return_span = fn_decl.output.span();
-                let return_ty = *sig.output().skip_binder();
+                let return_ty = sig.output().skip_binder();
 
                 // We expect the first argument to be a reference.
                 match argument_ty.kind {
diff --git a/src/librustc_mir/borrow_check/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/type_check/relate_tys.rs
index 285d9ed64691a..91b1a1fbd9705 100644
--- a/src/librustc_mir/borrow_check/type_check/relate_tys.rs
+++ b/src/librustc_mir/borrow_check/type_check/relate_tys.rs
@@ -31,7 +31,7 @@ pub(super) fn relate_types<'tcx>(
         NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
         v,
     )
-    .relate(&a, &b)?;
+    .relate(a, b)?;
     Ok(())
 }
 
diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs
index 88ba28dab82e1..01eb2d0b8e266 100644
--- a/src/librustc_mir/interpret/intrinsics.rs
+++ b/src/librustc_mir/interpret/intrinsics.rs
@@ -409,6 +409,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 );
                 self.copy_op(self.operand_index(args[0], index)?, dest)?;
             }
+            sym::likely | sym::unlikely => {
+                // These just return their argument
+                self.copy_op(args[0], dest)?;
+            }
             // FIXME(#73156): Handle source code coverage in const eval
             sym::count_code_region => (),
             _ => return Ok(false),
diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs
index ca1f0aecd048a..f00fc96e5915a 100644
--- a/src/librustc_mir/transform/check_consts/validation.rs
+++ b/src/librustc_mir/transform/check_consts/validation.rs
@@ -531,9 +531,12 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
                 if is_lang_panic_fn(self.tcx, def_id) {
                     self.check_op(ops::Panic);
                 } else if let Some(feature) = is_unstable_const_fn(self.tcx, def_id) {
-                    // Exempt unstable const fns inside of macros with
+                    // Exempt unstable const fns inside of macros or functions with
                     // `#[allow_internal_unstable]`.
-                    if !self.span.allows_unstable(feature) {
+                    use crate::transform::qualify_min_const_fn::lib_feature_allowed;
+                    if !self.span.allows_unstable(feature)
+                        && !lib_feature_allowed(self.tcx, self.def_id, feature)
+                    {
                         self.check_op(ops::FnCallUnstable(def_id, feature));
                     }
                 } else {
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index 5a3663384fb87..2f5257080cd5c 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -328,6 +328,26 @@ fn feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bo
         .map_or(false, |mut features| features.any(|name| name == feature_gate))
 }
 
+/// Returns `true` if the given library feature gate is allowed within the function with the given `DefId`.
+pub fn lib_feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool {
+    // All features require that the corresponding gate be enabled,
+    // even if the function has `#[allow_internal_unstable(the_gate)]`.
+    if !tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == feature_gate) {
+        return false;
+    }
+
+    // If this crate is not using stability attributes, or this function is not claiming to be a
+    // stable `const fn`, that is all that is required.
+    if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) {
+        return true;
+    }
+
+    // However, we cannot allow stable `const fn`s to use unstable features without an explicit
+    // opt-in via `allow_internal_unstable`.
+    attr::allow_internal_unstable(&tcx.get_attrs(def_id), &tcx.sess.diagnostic())
+        .map_or(false, |mut features| features.any(|name| name == feature_gate))
+}
+
 fn check_terminator(
     tcx: TyCtxt<'tcx>,
     body: &'a Body<'tcx>,
@@ -367,8 +387,17 @@ fn check_terminator(
             fn_span: _,
         } => {
             let fn_ty = func.ty(body, tcx);
-            if let ty::FnDef(def_id, _) = fn_ty.kind {
-                if !crate::const_eval::is_min_const_fn(tcx, def_id) {
+            if let ty::FnDef(fn_def_id, _) = fn_ty.kind {
+                // Allow unstable const if we opt in by using #[allow_internal_unstable]
+                // on function or macro declaration.
+                if !crate::const_eval::is_min_const_fn(tcx, fn_def_id)
+                    && !crate::const_eval::is_unstable_const_fn(tcx, fn_def_id)
+                        .map(|feature| {
+                            span.allows_unstable(feature)
+                                || lib_feature_allowed(tcx, def_id, feature)
+                        })
+                        .unwrap_or(false)
+                {
                     return Err((
                         span,
                         format!(
@@ -380,10 +409,10 @@ fn check_terminator(
                     ));
                 }
 
-                check_operand(tcx, func, span, def_id, body)?;
+                check_operand(tcx, func, span, fn_def_id, body)?;
 
                 for arg in args {
-                    check_operand(tcx, arg, span, def_id, body)?;
+                    check_operand(tcx, arg, span, fn_def_id, body)?;
                 }
                 Ok(())
             } else {
diff --git a/src/librustc_mir/transform/validate.rs b/src/librustc_mir/transform/validate.rs
index d3f486c815e6c..e794a6949d2f0 100644
--- a/src/librustc_mir/transform/validate.rs
+++ b/src/librustc_mir/transform/validate.rs
@@ -74,8 +74,8 @@ pub fn equal_up_to_regions(
         fn relate_with_variance<T: Relate<'tcx>>(
             &mut self,
             _: ty::Variance,
-            a: &T,
-            b: &T,
+            a: T,
+            b: T,
         ) -> RelateResult<'tcx, T> {
             // Ignore variance, require types to be exactly the same.
             self.relate(a, b)
@@ -108,8 +108,8 @@ pub fn equal_up_to_regions(
 
         fn binders<T>(
             &mut self,
-            a: &ty::Binder<T>,
-            b: &ty::Binder<T>,
+            a: ty::Binder<T>,
+            b: ty::Binder<T>,
         ) -> RelateResult<'tcx, ty::Binder<T>>
         where
             T: Relate<'tcx>,
@@ -121,7 +121,7 @@ pub fn equal_up_to_regions(
 
     // Instantiate and run relation.
     let mut relator: LifetimeIgnoreRelation<'tcx> = LifetimeIgnoreRelation { tcx: tcx, param_env };
-    relator.relate(&src, &dest).is_ok()
+    relator.relate(src, dest).is_ok()
 }
 
 struct TypeChecker<'a, 'tcx> {
diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs
index 6ac5d41ec6135..18b92bf29bf1b 100644
--- a/src/librustc_mir_build/hair/pattern/_match.rs
+++ b/src/librustc_mir_build/hair/pattern/_match.rs
@@ -4,8 +4,8 @@
 //! This file includes the logic for exhaustiveness and usefulness checking for
 //! pattern-matching. Specifically, given a list of patterns for a type, we can
 //! tell whether:
-//! (a) the patterns cover every possible constructor for the type [exhaustiveness]
-//! (b) each pattern is necessary [usefulness]
+//! (a) the patterns cover every possible constructor for the type (exhaustiveness)
+//! (b) each pattern is necessary (usefulness)
 //!
 //! The algorithm implemented here is a modified version of the one described in:
 //! http://moscova.inria.fr/~maranget/papers/warn/index.html
@@ -101,53 +101,54 @@
 //! To match the paper, the top of the stack is at the beginning / on the left.
 //!
 //! There are two important operations on pattern-stacks necessary to understand the algorithm:
-//!     1. We can pop a given constructor off the top of a stack. This operation is called
-//!        `specialize`, and is denoted `S(c, p)` where `c` is a constructor (like `Some` or
-//!        `None`) and `p` a pattern-stack.
-//!        If the pattern on top of the stack can cover `c`, this removes the constructor and
-//!        pushes its arguments onto the stack. It also expands OR-patterns into distinct patterns.
-//!        Otherwise the pattern-stack is discarded.
-//!        This essentially filters those pattern-stacks whose top covers the constructor `c` and
-//!        discards the others.
 //!
-//!        For example, the first pattern above initially gives a stack `[(Some(true), _)]`. If we
-//!        pop the tuple constructor, we are left with `[Some(true), _]`, and if we then pop the
-//!        `Some` constructor we get `[true, _]`. If we had popped `None` instead, we would get
-//!        nothing back.
+//! 1. We can pop a given constructor off the top of a stack. This operation is called
+//!    `specialize`, and is denoted `S(c, p)` where `c` is a constructor (like `Some` or
+//!    `None`) and `p` a pattern-stack.
+//!    If the pattern on top of the stack can cover `c`, this removes the constructor and
+//!    pushes its arguments onto the stack. It also expands OR-patterns into distinct patterns.
+//!    Otherwise the pattern-stack is discarded.
+//!    This essentially filters those pattern-stacks whose top covers the constructor `c` and
+//!    discards the others.
 //!
-//!        This returns zero or more new pattern-stacks, as follows. We look at the pattern `p_1`
-//!        on top of the stack, and we have four cases:
-//!             1.1. `p_1 = c(r_1, .., r_a)`, i.e. the top of the stack has constructor `c`. We
-//!                  push onto the stack the arguments of this constructor, and return the result:
-//!                     r_1, .., r_a, p_2, .., p_n
-//!             1.2. `p_1 = c'(r_1, .., r_a')` where `c ≠ c'`. We discard the current stack and
-//!                  return nothing.
-//!             1.3. `p_1 = _`. We push onto the stack as many wildcards as the constructor `c` has
-//!                  arguments (its arity), and return the resulting stack:
-//!                     _, .., _, p_2, .., p_n
-//!             1.4. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting
-//!                  stack:
-//!                     S(c, (r_1, p_2, .., p_n))
-//!                     S(c, (r_2, p_2, .., p_n))
+//!    For example, the first pattern above initially gives a stack `[(Some(true), _)]`. If we
+//!    pop the tuple constructor, we are left with `[Some(true), _]`, and if we then pop the
+//!    `Some` constructor we get `[true, _]`. If we had popped `None` instead, we would get
+//!    nothing back.
 //!
-//!     2. We can pop a wildcard off the top of the stack. This is called `D(p)`, where `p` is
-//!        a pattern-stack.
-//!        This is used when we know there are missing constructor cases, but there might be
-//!        existing wildcard patterns, so to check the usefulness of the matrix, we have to check
-//!        all its *other* components.
+//!    This returns zero or more new pattern-stacks, as follows. We look at the pattern `p_1`
+//!    on top of the stack, and we have four cases:
+//!         1.1. `p_1 = c(r_1, .., r_a)`, i.e. the top of the stack has constructor `c`. We
+//!              push onto the stack the arguments of this constructor, and return the result:
+//!                 r_1, .., r_a, p_2, .., p_n
+//!         1.2. `p_1 = c'(r_1, .., r_a')` where `c ≠ c'`. We discard the current stack and
+//!              return nothing.
+//!         1.3. `p_1 = _`. We push onto the stack as many wildcards as the constructor `c` has
+//!              arguments (its arity), and return the resulting stack:
+//!                 _, .., _, p_2, .., p_n
+//!         1.4. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting
+//!              stack:
+//!                 S(c, (r_1, p_2, .., p_n))
+//!                 S(c, (r_2, p_2, .., p_n))
 //!
-//!        It is computed as follows. We look at the pattern `p_1` on top of the stack,
-//!        and we have three cases:
-//!             1.1. `p_1 = c(r_1, .., r_a)`. We discard the current stack and return nothing.
-//!             1.2. `p_1 = _`. We return the rest of the stack:
-//!                     p_2, .., p_n
-//!             1.3. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting
-//!               stack.
-//!                     D((r_1, p_2, .., p_n))
-//!                     D((r_2, p_2, .., p_n))
+//! 2. We can pop a wildcard off the top of the stack. This is called `D(p)`, where `p` is
+//!    a pattern-stack.
+//!    This is used when we know there are missing constructor cases, but there might be
+//!    existing wildcard patterns, so to check the usefulness of the matrix, we have to check
+//!    all its *other* components.
 //!
-//!     Note that the OR-patterns are not always used directly in Rust, but are used to derive the
-//!     exhaustive integer matching rules, so they're written here for posterity.
+//!    It is computed as follows. We look at the pattern `p_1` on top of the stack,
+//!    and we have three cases:
+//!         1.1. `p_1 = c(r_1, .., r_a)`. We discard the current stack and return nothing.
+//!         1.2. `p_1 = _`. We return the rest of the stack:
+//!                 p_2, .., p_n
+//!         1.3. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting
+//!           stack.
+//!                 D((r_1, p_2, .., p_n))
+//!                 D((r_2, p_2, .., p_n))
+//!
+//! Note that the OR-patterns are not always used directly in Rust, but are used to derive the
+//! exhaustive integer matching rules, so they're written here for posterity.
 //!
 //! Both those operations extend straightforwardly to a list or pattern-stacks, i.e. a matrix, by
 //! working row-by-row. Popping a constructor ends up keeping only the matrix rows that start with
@@ -168,66 +169,66 @@
 //!
 //! Inductive step. (`n > 0`, i.e., whether there's at least one column
 //!                  [which may then be expanded into further columns later])
-//!     We're going to match on the top of the new pattern-stack, `p_1`.
-//!         - If `p_1 == c(r_1, .., r_a)`, i.e. we have a constructor pattern.
-//!           Then, the usefulness of `p_1` can be reduced to whether it is useful when
-//!           we ignore all the patterns in the first column of `P` that involve other constructors.
-//!           This is where `S(c, P)` comes in:
-//!           `U(P, p) := U(S(c, P), S(c, p))`
-//!           This special case is handled in `is_useful_specialized`.
+//! We're going to match on the top of the new pattern-stack, `p_1`.
+//!     - If `p_1 == c(r_1, .., r_a)`, i.e. we have a constructor pattern.
+//! Then, the usefulness of `p_1` can be reduced to whether it is useful when
+//! we ignore all the patterns in the first column of `P` that involve other constructors.
+//! This is where `S(c, P)` comes in:
+//! `U(P, p) := U(S(c, P), S(c, p))`
+//! This special case is handled in `is_useful_specialized`.
 //!
-//!           For example, if `P` is:
-//!           [
-//!               [Some(true), _],
-//!               [None, 0],
-//!           ]
-//!           and `p` is [Some(false), 0], then we don't care about row 2 since we know `p` only
-//!           matches values that row 2 doesn't. For row 1 however, we need to dig into the
-//!           arguments of `Some` to know whether some new value is covered. So we compute
-//!           `U([[true, _]], [false, 0])`.
+//! For example, if `P` is:
+//! [
+//! [Some(true), _],
+//! [None, 0],
+//! ]
+//! and `p` is [Some(false), 0], then we don't care about row 2 since we know `p` only
+//! matches values that row 2 doesn't. For row 1 however, we need to dig into the
+//! arguments of `Some` to know whether some new value is covered. So we compute
+//! `U([[true, _]], [false, 0])`.
 //!
-//!         - If `p_1 == _`, then we look at the list of constructors that appear in the first
-//!               component of the rows of `P`:
-//!             + If there are some constructors that aren't present, then we might think that the
-//!               wildcard `_` is useful, since it covers those constructors that weren't covered
-//!               before.
-//!               That's almost correct, but only works if there were no wildcards in those first
-//!               components. So we need to check that `p` is useful with respect to the rows that
-//!               start with a wildcard, if there are any. This is where `D` comes in:
-//!               `U(P, p) := U(D(P), D(p))`
+//!   - If `p_1 == _`, then we look at the list of constructors that appear in the first
+//! component of the rows of `P`:
+//!   + If there are some constructors that aren't present, then we might think that the
+//! wildcard `_` is useful, since it covers those constructors that weren't covered
+//! before.
+//! That's almost correct, but only works if there were no wildcards in those first
+//! components. So we need to check that `p` is useful with respect to the rows that
+//! start with a wildcard, if there are any. This is where `D` comes in:
+//! `U(P, p) := U(D(P), D(p))`
 //!
-//!               For example, if `P` is:
-//!               [
-//!                   [_, true, _],
-//!                   [None, false, 1],
-//!               ]
-//!               and `p` is [_, false, _], the `Some` constructor doesn't appear in `P`. So if we
-//!               only had row 2, we'd know that `p` is useful. However row 1 starts with a
-//!               wildcard, so we need to check whether `U([[true, _]], [false, 1])`.
+//! For example, if `P` is:
+//! [
+//!     [_, true, _],
+//!     [None, false, 1],
+//! ]
+//! and `p` is [_, false, _], the `Some` constructor doesn't appear in `P`. So if we
+//! only had row 2, we'd know that `p` is useful. However row 1 starts with a
+//! wildcard, so we need to check whether `U([[true, _]], [false, 1])`.
 //!
-//!             + Otherwise, all possible constructors (for the relevant type) are present. In this
-//!               case we must check whether the wildcard pattern covers any unmatched value. For
-//!               that, we can think of the `_` pattern as a big OR-pattern that covers all
-//!               possible constructors. For `Option`, that would mean `_ = None | Some(_)` for
-//!               example. The wildcard pattern is useful in this case if it is useful when
-//!               specialized to one of the possible constructors. So we compute:
-//!               `U(P, p) := ∃(k ϵ constructors) U(S(k, P), S(k, p))`
+//!   + Otherwise, all possible constructors (for the relevant type) are present. In this
+//! case we must check whether the wildcard pattern covers any unmatched value. For
+//! that, we can think of the `_` pattern as a big OR-pattern that covers all
+//! possible constructors. For `Option`, that would mean `_ = None | Some(_)` for
+//! example. The wildcard pattern is useful in this case if it is useful when
+//! specialized to one of the possible constructors. So we compute:
+//! `U(P, p) := ∃(k ϵ constructors) U(S(k, P), S(k, p))`
 //!
-//!               For example, if `P` is:
-//!               [
-//!                   [Some(true), _],
-//!                   [None, false],
-//!               ]
-//!               and `p` is [_, false], both `None` and `Some` constructors appear in the first
-//!               components of `P`. We will therefore try popping both constructors in turn: we
-//!               compute U([[true, _]], [_, false]) for the `Some` constructor, and U([[false]],
-//!               [false]) for the `None` constructor. The first case returns true, so we know that
-//!               `p` is useful for `P`. Indeed, it matches `[Some(false), _]` that wasn't matched
-//!               before.
+//! For example, if `P` is:
+//! [
+//!     [Some(true), _],
+//!     [None, false],
+//! ]
+//! and `p` is [_, false], both `None` and `Some` constructors appear in the first
+//! components of `P`. We will therefore try popping both constructors in turn: we
+//! compute `U([[true, _]], [_, false])` for the `Some` constructor, and `U([[false]],
+//! [false])` for the `None` constructor. The first case returns true, so we know that
+//! `p` is useful for `P`. Indeed, it matches `[Some(false), _]` that wasn't matched
+//! before.
 //!
-//!         - If `p_1 == r_1 | r_2`, then the usefulness depends on each `r_i` separately:
-//!           `U(P, p) := U(P, (r_1, p_2, .., p_n))
-//!                    || U(P, (r_2, p_2, .., p_n))`
+//!   - If `p_1 == r_1 | r_2`, then the usefulness depends on each `r_i` separately:
+//! `U(P, p) := U(P, (r_1, p_2, .., p_n))
+//!  || U(P, (r_2, p_2, .., p_n))`
 //!
 //! Modifications to the algorithm
 //! ------------------------------
diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs
index fc9ffc3092447..16a118cb48c91 100644
--- a/src/librustc_parse/parser/diagnostics.rs
+++ b/src/librustc_parse/parser/diagnostics.rs
@@ -376,7 +376,14 @@ impl<'a> Parser<'a> {
     /// let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>();
     ///                                                        ^^ help: remove extra angle brackets
     /// ```
-    pub(super) fn check_trailing_angle_brackets(&mut self, segment: &PathSegment, end: TokenKind) {
+    ///
+    /// If `true` is returned, then trailing brackets were recovered, tokens were consumed
+    /// up until one of the tokens in 'end' was encountered, and an error was emitted.
+    pub(super) fn check_trailing_angle_brackets(
+        &mut self,
+        segment: &PathSegment,
+        end: &[&TokenKind],
+    ) -> bool {
         // This function is intended to be invoked after parsing a path segment where there are two
         // cases:
         //
@@ -409,7 +416,7 @@ impl<'a> Parser<'a> {
             parsed_angle_bracket_args,
         );
         if !parsed_angle_bracket_args {
-            return;
+            return false;
         }
 
         // Keep the span at the start so we can highlight the sequence of `>` characters to be
@@ -447,18 +454,18 @@ impl<'a> Parser<'a> {
             number_of_gt, number_of_shr,
         );
         if number_of_gt < 1 && number_of_shr < 1 {
-            return;
+            return false;
         }
 
         // Finally, double check that we have our end token as otherwise this is the
         // second case.
         if self.look_ahead(position, |t| {
             trace!("check_trailing_angle_brackets: t={:?}", t);
-            *t == end
+            end.contains(&&t.kind)
         }) {
             // Eat from where we started until the end token so that parsing can continue
             // as if we didn't have those extra angle brackets.
-            self.eat_to_tokens(&[&end]);
+            self.eat_to_tokens(end);
             let span = lo.until(self.token.span);
 
             let total_num_of_gt = number_of_gt + number_of_shr * 2;
@@ -473,7 +480,9 @@ impl<'a> Parser<'a> {
                 Applicability::MachineApplicable,
             )
             .emit();
+            return true;
         }
+        false
     }
 
     /// Check to see if a pair of chained operators looks like an attempt at chained comparison,
@@ -1415,7 +1424,7 @@ impl<'a> Parser<'a> {
                 if self.token != token::Lt {
                     err.span_suggestion(
                         pat.span,
-                        "if this was a parameter name, give it a type",
+                        "if this is a parameter name, give it a type",
                         format!("{}: TypeName", ident),
                         Applicability::HasPlaceholders,
                     );
diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs
index 2745b18a8cd51..fb38fdc26c782 100644
--- a/src/librustc_parse/parser/expr.rs
+++ b/src/librustc_parse/parser/expr.rs
@@ -867,7 +867,7 @@ impl<'a> Parser<'a> {
 
         let fn_span_lo = self.token.span;
         let segment = self.parse_path_segment(PathStyle::Expr)?;
-        self.check_trailing_angle_brackets(&segment, token::OpenDelim(token::Paren));
+        self.check_trailing_angle_brackets(&segment, &[&token::OpenDelim(token::Paren)]);
 
         if self.check(&token::OpenDelim(token::Paren)) {
             // Method call `expr.f()`
diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs
index 10df16964da08..fa6264c98e4f0 100644
--- a/src/librustc_parse/parser/item.rs
+++ b/src/librustc_parse/parser/item.rs
@@ -9,7 +9,7 @@ use rustc_ast::ast::{AssocItem, AssocItemKind, ForeignItemKind, Item, ItemKind,
 use rustc_ast::ast::{Async, Const, Defaultness, IsAuto, Mutability, Unsafe, UseTree, UseTreeKind};
 use rustc_ast::ast::{BindingMode, Block, FnDecl, FnSig, Param, SelfKind};
 use rustc_ast::ast::{EnumDef, Generics, StructField, TraitRef, Ty, TyKind, Variant, VariantData};
-use rustc_ast::ast::{FnHeader, ForeignItem, PathSegment, Visibility, VisibilityKind};
+use rustc_ast::ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, VisibilityKind};
 use rustc_ast::ast::{MacArgs, MacCall, MacDelimiter};
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, TokenKind};
@@ -1262,6 +1262,25 @@ impl<'a> Parser<'a> {
                     sp,
                     &format!("expected `,`, or `}}`, found {}", super::token_descr(&self.token)),
                 );
+
+                // Try to recover extra trailing angle brackets
+                let mut recovered = false;
+                if let TyKind::Path(_, Path { segments, .. }) = &a_var.ty.kind {
+                    if let Some(last_segment) = segments.last() {
+                        recovered = self.check_trailing_angle_brackets(
+                            last_segment,
+                            &[&token::Comma, &token::CloseDelim(token::Brace)],
+                        );
+                        if recovered {
+                            // Handle a case like `Vec<u8>>,` where we can continue parsing fields
+                            // after the comma
+                            self.eat(&token::Comma);
+                            // `check_trailing_angle_brackets` already emitted a nicer error
+                            err.cancel();
+                        }
+                    }
+                }
+
                 if self.token.is_ident() {
                     // This is likely another field; emit the diagnostic and keep going
                     err.span_suggestion(
@@ -1271,6 +1290,14 @@ impl<'a> Parser<'a> {
                         Applicability::MachineApplicable,
                     );
                     err.emit();
+                    recovered = true;
+                }
+
+                if recovered {
+                    // Make sure an error was emitted (either by recovering an angle bracket,
+                    // or by finding an identifier as the next token), since we're
+                    // going to continue parsing
+                    assert!(self.sess.span_diagnostic.has_errors());
                 } else {
                     return Err(err);
                 }
diff --git a/src/librustc_parse/parser/path.rs b/src/librustc_parse/parser/path.rs
index 5210614548da3..67e9b3af4a8cf 100644
--- a/src/librustc_parse/parser/path.rs
+++ b/src/librustc_parse/parser/path.rs
@@ -169,7 +169,7 @@ impl<'a> Parser<'a> {
                 // `PathStyle::Expr` is only provided at the root invocation and never in
                 // `parse_path_segment` to recurse and therefore can be checked to maintain
                 // this invariant.
-                self.check_trailing_angle_brackets(&segment, token::ModSep);
+                self.check_trailing_angle_brackets(&segment, &[&token::ModSep]);
             }
             segments.push(segment);
 
diff --git a/src/librustc_passes/intrinsicck.rs b/src/librustc_passes/intrinsicck.rs
index 683039df15ac6..e4f4885690fd9 100644
--- a/src/librustc_passes/intrinsicck.rs
+++ b/src/librustc_passes/intrinsicck.rs
@@ -422,7 +422,7 @@ impl Visitor<'tcx> for ExprVisitor<'tcx> {
                         let typ = self.tables.node_type(expr.hir_id);
                         let sig = typ.fn_sig(self.tcx);
                         let from = sig.inputs().skip_binder()[0];
-                        let to = *sig.output().skip_binder();
+                        let to = sig.output().skip_binder();
                         self.check_transmute(expr.span, from, to);
                     }
                 }
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 9e6e7ea962bc3..20f09ef52f00b 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -92,14 +92,14 @@ where
         for (predicate, _span) in predicates {
             match predicate.kind() {
                 ty::PredicateKind::Trait(poly_predicate, _) => {
-                    let ty::TraitPredicate { trait_ref } = *poly_predicate.skip_binder();
+                    let ty::TraitPredicate { trait_ref } = poly_predicate.skip_binder();
                     if self.visit_trait(trait_ref) {
                         return true;
                     }
                 }
                 ty::PredicateKind::Projection(poly_predicate) => {
                     let ty::ProjectionPredicate { projection_ty, ty } =
-                        *poly_predicate.skip_binder();
+                        poly_predicate.skip_binder();
                     if ty.visit_with(self) {
                         return true;
                     }
@@ -108,7 +108,7 @@ where
                     }
                 }
                 ty::PredicateKind::TypeOutlives(poly_predicate) => {
-                    let ty::OutlivesPredicate(ty, _region) = *poly_predicate.skip_binder();
+                    let ty::OutlivesPredicate(ty, _region) = poly_predicate.skip_binder();
                     if ty.visit_with(self) {
                         return true;
                     }
@@ -175,7 +175,7 @@ where
             ty::Dynamic(predicates, ..) => {
                 // All traits in the list are considered the "primary" part of the type
                 // and are visited by shallow visitors.
-                for predicate in *predicates.skip_binder() {
+                for predicate in predicates.skip_binder() {
                     let trait_ref = match predicate {
                         ty::ExistentialPredicate::Trait(trait_ref) => trait_ref,
                         ty::ExistentialPredicate::Projection(proj) => proj.trait_ref(tcx),
@@ -1270,7 +1270,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
             );
 
             for (trait_predicate, _, _) in bounds.trait_bounds {
-                if self.visit_trait(*trait_predicate.skip_binder()) {
+                if self.visit_trait(trait_predicate.skip_binder()) {
                     return;
                 }
             }
diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs
index 857734037afe7..e67ca3259ff6b 100644
--- a/src/librustc_span/symbol.rs
+++ b/src/librustc_span/symbol.rs
@@ -152,10 +152,14 @@ symbols! {
         arm_target_feature,
         asm,
         assert,
+        assert_inhabited,
+        assert_uninit_valid,
+        assert_zero_valid,
         associated_consts,
         associated_type_bounds,
         associated_type_defaults,
         associated_types,
+        assume,
         assume_init,
         async_await,
         async_closure,
@@ -181,11 +185,14 @@ symbols! {
         box_patterns,
         box_syntax,
         braced_empty_structs,
+        breakpoint,
         bswap,
         bitreverse,
         C,
         caller_location,
         cdylib,
+        ceilf32,
+        ceilf64,
         cfg,
         cfg_accessible,
         cfg_attr,
@@ -239,8 +246,14 @@ symbols! {
         convert,
         Copy,
         copy_closures,
+        copy,
+        copy_nonoverlapping,
+        copysignf32,
+        copysignf64,
         core,
         core_intrinsics,
+        cosf32,
+        cosf64,
         count_code_region,
         crate_id,
         crate_in_paths,
@@ -296,6 +309,7 @@ symbols! {
         dropck_eyepatch,
         dropck_parametricity,
         drop_types_in_const,
+        drop_in_place,
         dylib,
         dyn_trait,
         eh_personality,
@@ -308,11 +322,16 @@ symbols! {
         Eq,
         Equal,
         enclosing_scope,
+        exact_div,
         except,
         exclusive_range_pattern,
         exhaustive_integer_patterns,
         exhaustive_patterns,
         existential_type,
+        expf32,
+        expf64,
+        exp2f32,
+        exp2f64,
         expected,
         export_name,
         expr,
@@ -326,6 +345,10 @@ symbols! {
         f16c_target_feature,
         f32,
         f64,
+        fadd_fast,
+        fabsf32,
+        fabsf64,
+        fdiv_fast,
         feature,
         ffi_const,
         ffi_pure,
@@ -333,12 +356,20 @@ symbols! {
         field,
         field_init_shorthand,
         file,
+        float_to_int_unchecked,
+        floorf64,
+        floorf32,
+        fmaf32,
+        fmaf64,
         fmt,
         fmt_internals,
+        fmul_fast,
         fn_must_use,
         forbid,
+        forget,
         format_args,
         format_args_nl,
+        frem_fast,
         from,
         From,
         from_desugaring,
@@ -348,6 +379,7 @@ symbols! {
         from_ok,
         from_usize,
         from_trait,
+        fsub_fast,
         fundamental,
         future,
         Future,
@@ -427,6 +459,7 @@ symbols! {
         lhs,
         lib,
         lifetime,
+        likely,
         line,
         link,
         linkage,
@@ -442,6 +475,12 @@ symbols! {
         llvm_asm,
         local_inner_macros,
         log_syntax,
+        logf32,
+        logf64,
+        log10f32,
+        log10f64,
+        log2f32,
+        log2f64,
         loop_break_value,
         macro_at_most_once_rep,
         macro_escape,
@@ -469,10 +508,16 @@ symbols! {
         message,
         meta,
         min_align_of,
+        min_align_of_val,
         min_const_fn,
         min_const_unsafe_fn,
         min_specialization,
+        minnumf32,
+        minnumf64,
+        maxnumf32,
+        maxnumf64,
         mips_target_feature,
+        miri_start_panic,
         mmx_target_feature,
         module,
         module_path,
@@ -485,6 +530,8 @@ symbols! {
         naked,
         naked_functions,
         name,
+        nearbyintf32,
+        nearbyintf64,
         needs_allocator,
         needs_drop,
         needs_panic_runtime,
@@ -512,6 +559,7 @@ symbols! {
         None,
         non_exhaustive,
         non_modrs_mods,
+        nontemporal_store,
         noreturn,
         no_niche,
         no_sanitize,
@@ -570,8 +618,16 @@ symbols! {
         poll,
         Poll,
         powerpc_target_feature,
+        powf32,
+        powf64,
+        powif32,
+        powif64,
         precise_pointer_size_matching,
         pref_align_of,
+        prefetch_read_data,
+        prefetch_read_instruction,
+        prefetch_write_data,
+        prefetch_write_instruction,
         prelude,
         prelude_import,
         preserves_flags,
@@ -631,10 +687,14 @@ symbols! {
         Result,
         Return,
         rhs,
+        rintf32,
+        rintf64,
         riscv_target_feature,
         rlib,
         rotate_left,
         rotate_right,
+        roundf32,
+        roundf64,
         rt,
         rtm_target_feature,
         rust,
@@ -717,14 +777,19 @@ symbols! {
         simd_ffi,
         simd_insert,
         since,
+        sinf32,
+        sinf64,
         size,
         size_of,
+        size_of_val,
         slice_patterns,
         slicing_syntax,
         soft,
         Some,
         specialization,
         speed,
+        sqrtf32,
+        sqrtf64,
         sse4a_target_feature,
         stable,
         staged_api,
@@ -778,6 +843,8 @@ symbols! {
         transparent_enums,
         transparent_unions,
         trivial_bounds,
+        truncf32,
+        truncf64,
         Try,
         try_blocks,
         try_trait,
@@ -800,6 +867,8 @@ symbols! {
         u32,
         u64,
         u8,
+        unaligned_volatile_load,
+        unaligned_volatile_store,
         unboxed_closures,
         unchecked_add,
         unchecked_div,
@@ -813,7 +882,9 @@ symbols! {
         underscore_lifetimes,
         uniform_paths,
         universal_impl_trait,
+        unlikely,
         unmarked_api,
+        unreachable,
         unreachable_code,
         unrestricted_attribute_tokens,
         unsafe_block_in_unsafe_fn,
@@ -833,12 +904,21 @@ symbols! {
         val,
         var,
         variant_count,
+        va_arg,
+        va_copy,
+        va_end,
+        va_start,
         vec,
         Vec,
         version,
         vis,
         visible_private_types,
         volatile,
+        volatile_copy_memory,
+        volatile_copy_nonoverlapping_memory,
+        volatile_load,
+        volatile_set_memory,
+        volatile_store,
         warn,
         wasm_import_module,
         wasm_target_feature,
@@ -848,6 +928,7 @@ symbols! {
         wrapping_add,
         wrapping_sub,
         wrapping_mul,
+        write_bytes,
         Yield,
     }
 }
diff --git a/src/librustc_symbol_mangling/v0.rs b/src/librustc_symbol_mangling/v0.rs
index 7d117b77cf5e5..ecf27fbf54220 100644
--- a/src/librustc_symbol_mangling/v0.rs
+++ b/src/librustc_symbol_mangling/v0.rs
@@ -219,7 +219,7 @@ impl SymbolMangler<'tcx> {
         lifetime_depths.end += lifetimes;
 
         self.binders.push(BinderLevel { lifetime_depths });
-        self = print_value(self, value.skip_binder())?;
+        self = print_value(self, value.as_ref().skip_binder())?;
         self.binders.pop();
 
         Ok(self)
diff --git a/src/librustc_trait_selection/opaque_types.rs b/src/librustc_trait_selection/opaque_types.rs
index adccdd0b2617a..ce478de7c755c 100644
--- a/src/librustc_trait_selection/opaque_types.rs
+++ b/src/librustc_trait_selection/opaque_types.rs
@@ -691,7 +691,7 @@ where
     OP: FnMut(ty::Region<'tcx>),
 {
     fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool {
-        t.skip_binder().visit_with(self);
+        t.as_ref().skip_binder().visit_with(self);
         false // keep visiting
     }
 
diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs
index fd0c1a54d27ad..49e43873df759 100644
--- a/src/librustc_trait_selection/traits/error_reporting/mod.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs
@@ -1569,7 +1569,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
                     // no need to overload user in such cases
                     return;
                 }
-                let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder();
+                let SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder();
                 // both must be type variables, or the other would've been instantiated
                 assert!(a.is_ty_var() && b.is_ty_var());
                 self.need_type_info_err(body_id, span, a, ErrorCode::E0282)
diff --git a/src/librustc_trait_selection/traits/error_reporting/on_unimplemented.rs b/src/librustc_trait_selection/traits/error_reporting/on_unimplemented.rs
index fd87759a7621f..ec51dddc2c810 100644
--- a/src/librustc_trait_selection/traits/error_reporting/on_unimplemented.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/on_unimplemented.rs
@@ -122,7 +122,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
     ) -> OnUnimplementedNote {
         let def_id =
             self.impl_similar_to(trait_ref, obligation).unwrap_or_else(|| trait_ref.def_id());
-        let trait_ref = *trait_ref.skip_binder();
+        let trait_ref = trait_ref.skip_binder();
 
         let mut flags = vec![];
         flags.push((
@@ -219,7 +219,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             }
         }
         if let ty::Dynamic(traits, _) = self_ty.kind {
-            for t in *traits.skip_binder() {
+            for t in traits.skip_binder() {
                 if let ty::ExistentialPredicate::Trait(trait_ref) = t {
                     flags.push((sym::_Self, Some(self.tcx.def_path_str(trait_ref.def_id))))
                 }
diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
index 176bd90303ddd..1fafa9ec035ce 100644
--- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
@@ -1179,7 +1179,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
     ) -> DiagnosticBuilder<'tcx> {
         crate fn build_fn_sig_string<'tcx>(
             tcx: TyCtxt<'tcx>,
-            trait_ref: &ty::TraitRef<'tcx>,
+            trait_ref: ty::TraitRef<'tcx>,
         ) -> String {
             let inputs = trait_ref.substs.type_at(1);
             let sig = if let ty::Tuple(inputs) = inputs.kind {
@@ -1360,7 +1360,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                         }
                         ty::GeneratorWitness(..) => {}
                         _ if generator.is_none() => {
-                            trait_ref = Some(*derived_obligation.parent_trait_ref.skip_binder());
+                            trait_ref = Some(derived_obligation.parent_trait_ref.skip_binder());
                             target_ty = Some(ty);
                         }
                         _ => {}
diff --git a/src/librustc_trait_selection/traits/select/candidate_assembly.rs b/src/librustc_trait_selection/traits/select/candidate_assembly.rs
index 4dab5814f7b7e..91c162872b215 100644
--- a/src/librustc_trait_selection/traits/select/candidate_assembly.rs
+++ b/src/librustc_trait_selection/traits/select/candidate_assembly.rs
@@ -220,7 +220,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // Okay to skip binder because the substs on generator types never
         // touch bound regions, they just capture the in-scope
         // type/region parameters.
-        let self_ty = *obligation.self_ty().skip_binder();
+        let self_ty = obligation.self_ty().skip_binder();
         match self_ty.kind {
             ty::Generator(..) => {
                 debug!(
@@ -299,7 +299,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         }
 
         // Okay to skip binder because what we are inspecting doesn't involve bound regions.
-        let self_ty = *obligation.self_ty().skip_binder();
+        let self_ty = obligation.self_ty().skip_binder();
         match self_ty.kind {
             ty::Infer(ty::TyVar(_)) => {
                 debug!("assemble_fn_pointer_candidates: ambiguous self-type");
@@ -362,7 +362,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         candidates: &mut SelectionCandidateSet<'tcx>,
     ) -> Result<(), SelectionError<'tcx>> {
         // Okay to skip binder here because the tests we do below do not involve bound regions.
-        let self_ty = *obligation.self_ty().skip_binder();
+        let self_ty = obligation.self_ty().skip_binder();
         debug!("assemble_candidates_from_auto_impls(self_ty={:?})", self_ty);
 
         let def_id = obligation.predicate.def_id();
@@ -583,7 +583,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         candidates: &mut SelectionCandidateSet<'tcx>,
     ) -> Result<(), SelectionError<'tcx>> {
         // Okay to skip binder here because the tests we do below do not involve bound regions.
-        let self_ty = *obligation.self_ty().skip_binder();
+        let self_ty = obligation.self_ty().skip_binder();
         debug!("assemble_candidates_for_trait_alias(self_ty={:?})", self_ty);
 
         let def_id = obligation.predicate.def_id();
diff --git a/src/librustc_trait_selection/traits/select/confirmation.rs b/src/librustc_trait_selection/traits/select/confirmation.rs
index 834bf17227d2e..fa970589bbbf6 100644
--- a/src/librustc_trait_selection/traits/select/confirmation.rs
+++ b/src/librustc_trait_selection/traits/select/confirmation.rs
@@ -326,7 +326,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // probably flatten the binder from the obligation and the binder
         // from the object. Have to try to make a broken test case that
         // results.
-        let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
+        let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
         let poly_trait_ref = match self_ty.kind {
             ty::Dynamic(ref data, ..) => data
                 .principal()
@@ -379,7 +379,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         debug!("confirm_fn_pointer_candidate({:?})", obligation);
 
         // Okay to skip binder; it is reintroduced below.
-        let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
+        let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
         let sig = self_ty.fn_sig(self.tcx());
         let trait_ref = closure_trait_ref_and_return_type(
             self.tcx(),
@@ -448,7 +448,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // Okay to skip binder because the substs on generator types never
         // touch bound regions, they just capture the in-scope
         // type/region parameters.
-        let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
+        let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
         let (generator_def_id, substs) = match self_ty.kind {
             ty::Generator(id, substs, _) => (id, substs),
             _ => bug!("closure candidate for non-closure {:?}", obligation),
@@ -497,7 +497,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // Okay to skip binder because the substs on closure types never
         // touch bound regions, they just capture the in-scope
         // type/region parameters.
-        let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
+        let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
         let (closure_def_id, substs) = match self_ty.kind {
             ty::Closure(id, substs) => (id, substs),
             _ => bug!("closure candidate for non-closure {:?}", obligation),
diff --git a/src/librustc_trait_selection/traits/select/mod.rs b/src/librustc_trait_selection/traits/select/mod.rs
index cff5efbfd0fd1..c41a27c6f431f 100644
--- a/src/librustc_trait_selection/traits/select/mod.rs
+++ b/src/librustc_trait_selection/traits/select/mod.rs
@@ -748,8 +748,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             && stack.iter().skip(1).any(|prev| {
                 stack.obligation.param_env == prev.obligation.param_env
                     && self.match_fresh_trait_refs(
-                        &stack.fresh_trait_ref,
-                        &prev.fresh_trait_ref,
+                        stack.fresh_trait_ref,
+                        prev.fresh_trait_ref,
                         prev.obligation.param_env,
                     )
             })
@@ -1944,8 +1944,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
     fn match_fresh_trait_refs(
         &self,
-        previous: &ty::PolyTraitRef<'tcx>,
-        current: &ty::PolyTraitRef<'tcx>,
+        previous: ty::PolyTraitRef<'tcx>,
+        current: ty::PolyTraitRef<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> bool {
         let mut matcher = ty::_match::Match::new(self.tcx(), param_env);
diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs
index 1825c159ff3fb..ebff2dd9b23c1 100644
--- a/src/librustc_trait_selection/traits/wf.rs
+++ b/src/librustc_trait_selection/traits/wf.rs
@@ -695,7 +695,7 @@ pub fn object_region_bounds<'tcx>(
     let open_ty = tcx.mk_ty_infer(ty::FreshTy(0));
 
     let predicates = existential_predicates.iter().filter_map(|predicate| {
-        if let ty::ExistentialPredicate::Projection(_) = *predicate.skip_binder() {
+        if let ty::ExistentialPredicate::Projection(_) = predicate.skip_binder() {
             None
         } else {
             Some(predicate.with_self_ty(tcx, open_ty))
diff --git a/src/librustc_traits/chalk/lowering.rs b/src/librustc_traits/chalk/lowering.rs
index e09359b8b3fc1..ed021e5b9de1b 100644
--- a/src/librustc_traits/chalk/lowering.rs
+++ b/src/librustc_traits/chalk/lowering.rs
@@ -615,7 +615,7 @@ crate fn collect_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>>(
     ty: &'a Binder<T>,
 ) -> (T, chalk_ir::VariableKinds<RustInterner<'tcx>>, BTreeMap<DefId, u32>) {
     let mut bound_vars_collector = BoundVarsCollector::new();
-    ty.skip_binder().visit_with(&mut bound_vars_collector);
+    ty.as_ref().skip_binder().visit_with(&mut bound_vars_collector);
     let mut parameters = bound_vars_collector.parameters;
     let named_parameters: BTreeMap<DefId, u32> = bound_vars_collector
         .named_parameters
@@ -625,7 +625,7 @@ crate fn collect_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>>(
         .collect();
 
     let mut bound_var_substitutor = NamedBoundVarSubstitutor::new(tcx, &named_parameters);
-    let new_ty = ty.skip_binder().fold_with(&mut bound_var_substitutor);
+    let new_ty = ty.as_ref().skip_binder().fold_with(&mut bound_var_substitutor);
 
     for var in named_parameters.values() {
         parameters.insert(*var, chalk_ir::VariableKind::Lifetime);
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 1b08bf2fc7710..5d1949626dd84 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1802,7 +1802,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
         // Calling `skip_binder` is okay because the predicates are re-bound.
         let regular_trait_predicates = existential_trait_refs
-            .map(|trait_ref| ty::ExistentialPredicate::Trait(*trait_ref.skip_binder()));
+            .map(|trait_ref| ty::ExistentialPredicate::Trait(trait_ref.skip_binder()));
         let auto_trait_predicates = auto_traits
             .into_iter()
             .map(|trait_ref| ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id()));
@@ -1810,7 +1810,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             .chain(auto_trait_predicates)
             .chain(
                 existential_projections
-                    .map(|x| ty::ExistentialPredicate::Projection(*x.skip_binder())),
+                    .map(|x| ty::ExistentialPredicate::Projection(x.skip_binder())),
             )
             .collect::<SmallVec<[_; 8]>>();
         v.sort_by(|a, b| a.stable_cmp(tcx, b));
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 6d09ddc925ffe..fce2b18b782fb 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -188,7 +188,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             ty::Infer(ty::TyVar(vid)) => self.deduce_expectations_from_obligations(vid),
             ty::FnPtr(sig) => {
-                let expected_sig = ExpectedSig { cause_span: None, sig: *sig.skip_binder() };
+                let expected_sig = ExpectedSig { cause_span: None, sig: sig.skip_binder() };
                 (Some(expected_sig), Some(ty::ClosureKind::Fn))
             }
             _ => (None, None),
@@ -501,7 +501,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             for ((hir_ty, &supplied_ty), expected_ty) in decl
                 .inputs
                 .iter()
-                .zip(*supplied_sig.inputs().skip_binder()) // binder moved to (*) below
+                .zip(supplied_sig.inputs().skip_binder()) // binder moved to (*) below
                 .zip(expected_sigs.liberated_sig.inputs())
             // `liberated_sig` is E'.
             {
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index b6cd8da236260..e6b3224050e9b 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -964,7 +964,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let sig = self
                 .at(cause, self.param_env)
                 .trace(prev_ty, new_ty)
-                .lub(&a_sig, &b_sig)
+                .lub(a_sig, b_sig)
                 .map(|ok| self.register_infer_ok_obligations(ok))?;
 
             // Reify both sides and return the reified fn pointer type.
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 4e97ba41dcbb3..e6217e0cc1b6e 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -502,7 +502,7 @@ fn compare_self_type<'tcx>(
             ty::ImplContainer(_) => impl_trait_ref.self_ty(),
             ty::TraitContainer(_) => tcx.types.self_param,
         };
-        let self_arg_ty = *tcx.fn_sig(method.def_id).input(0).skip_binder();
+        let self_arg_ty = tcx.fn_sig(method.def_id).input(0).skip_binder();
         let param_env = ty::ParamEnv::reveal_all();
 
         tcx.infer_ctxt().enter(|infcx| {
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index e27c2e4503910..f6991120f3479 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -227,10 +227,10 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
         let predicate_matches_closure = |p: Predicate<'tcx>| {
             let mut relator: SimpleEqRelation<'tcx> = SimpleEqRelation::new(tcx, self_param_env);
             match (predicate.kind(), p.kind()) {
-                (ty::PredicateKind::Trait(a, _), ty::PredicateKind::Trait(b, _)) => {
+                (&ty::PredicateKind::Trait(a, _), &ty::PredicateKind::Trait(b, _)) => {
                     relator.relate(a, b).is_ok()
                 }
-                (ty::PredicateKind::Projection(a), ty::PredicateKind::Projection(b)) => {
+                (&ty::PredicateKind::Projection(a), &ty::PredicateKind::Projection(b)) => {
                     relator.relate(a, b).is_ok()
                 }
                 _ => predicate == p,
@@ -310,8 +310,8 @@ impl TypeRelation<'tcx> for SimpleEqRelation<'tcx> {
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         _: ty::Variance,
-        a: &T,
-        b: &T,
+        a: T,
+        b: T,
     ) -> RelateResult<'tcx, T> {
         // Here we ignore variance because we require drop impl's types
         // to be *exactly* the same as to the ones in the struct definition.
@@ -354,8 +354,8 @@ impl TypeRelation<'tcx> for SimpleEqRelation<'tcx> {
 
     fn binders<T>(
         &mut self,
-        a: &ty::Binder<T>,
-        b: &ty::Binder<T>,
+        a: ty::Binder<T>,
+        b: ty::Binder<T>,
     ) -> RelateResult<'tcx, ty::Binder<T>>
     where
         T: Relate<'tcx>,
@@ -364,8 +364,8 @@ impl TypeRelation<'tcx> for SimpleEqRelation<'tcx> {
 
         // Anonymizing the LBRs is necessary to solve (Issue #59497).
         // After we do so, it should be totally fine to skip the binders.
-        let anon_a = self.tcx.anonymize_late_bound_regions(a);
-        let anon_b = self.tcx.anonymize_late_bound_regions(b);
+        let anon_a = self.tcx.anonymize_late_bound_regions(&a);
+        let anon_b = self.tcx.anonymize_late_bound_regions(&b);
         self.relate(anon_a.skip_binder(), anon_b.skip_binder())?;
 
         Ok(a.clone())
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index 1c0b22ca7370b..62e62435a08ea 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -5,10 +5,11 @@ use crate::require_same_types;
 
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
 use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_span::symbol::Symbol;
+use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_target::spec::abi::Abi;
 
 use std::iter;
@@ -16,14 +17,13 @@ use std::iter;
 fn equate_intrinsic_type<'tcx>(
     tcx: TyCtxt<'tcx>,
     it: &hir::ForeignItem<'_>,
+    def_id: DefId,
     n_tps: usize,
     abi: Abi,
     safety: hir::Unsafety,
     inputs: Vec<Ty<'tcx>>,
     output: Ty<'tcx>,
 ) {
-    let def_id = tcx.hir().local_def_id(it.hir_id);
-
     match it.kind {
         hir::ForeignItemKind::Fn(..) => {}
         _ => {
@@ -67,15 +67,43 @@ fn equate_intrinsic_type<'tcx>(
 }
 
 /// Returns `true` if the given intrinsic is unsafe to call or not.
-pub fn intrinsic_operation_unsafety(intrinsic: &str) -> hir::Unsafety {
+pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety {
     match intrinsic {
-        "abort" | "size_of" | "min_align_of" | "needs_drop" | "caller_location" | "size_of_val"
-        | "min_align_of_val" | "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow"
-        | "wrapping_add" | "wrapping_sub" | "wrapping_mul" | "saturating_add"
-        | "saturating_sub" | "rotate_left" | "rotate_right" | "ctpop" | "ctlz" | "cttz"
-        | "bswap" | "bitreverse" | "discriminant_value" | "type_id" | "likely" | "unlikely"
-        | "ptr_guaranteed_eq" | "ptr_guaranteed_ne" | "minnumf32" | "minnumf64" | "maxnumf32"
-        | "maxnumf64" | "type_name" | "variant_count" => hir::Unsafety::Normal,
+        sym::abort
+        | sym::size_of
+        | sym::min_align_of
+        | sym::needs_drop
+        | sym::caller_location
+        | sym::size_of_val
+        | sym::min_align_of_val
+        | sym::add_with_overflow
+        | sym::sub_with_overflow
+        | sym::mul_with_overflow
+        | sym::wrapping_add
+        | sym::wrapping_sub
+        | sym::wrapping_mul
+        | sym::saturating_add
+        | sym::saturating_sub
+        | sym::rotate_left
+        | sym::rotate_right
+        | sym::ctpop
+        | sym::ctlz
+        | sym::cttz
+        | sym::bswap
+        | sym::bitreverse
+        | sym::discriminant_value
+        | sym::type_id
+        | sym::likely
+        | sym::unlikely
+        | sym::ptr_guaranteed_eq
+        | sym::ptr_guaranteed_ne
+        | sym::minnumf32
+        | sym::minnumf64
+        | sym::maxnumf32
+        | sym::rustc_peek
+        | sym::maxnumf64
+        | sym::type_name
+        | sym::variant_count => hir::Unsafety::Normal,
         _ => hir::Unsafety::Unsafe,
     }
 }
@@ -84,7 +112,9 @@ pub fn intrinsic_operation_unsafety(intrinsic: &str) -> hir::Unsafety {
 /// and in libcore/intrinsics.rs
 pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
     let param = |n| tcx.mk_ty_param(n, Symbol::intern(&format!("P{}", n)));
-    let name = it.ident.as_str();
+    let def_id = tcx.hir().local_def_id(it.hir_id).to_def_id();
+    let intrinsic_name = tcx.item_name(def_id);
+    let name_str = intrinsic_name.as_str();
 
     let mk_va_list_ty = |mutbl| {
         tcx.lang_items().va_list().map(|did| {
@@ -98,8 +128,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
         })
     };
 
-    let (n_tps, inputs, output, unsafety) = if name.starts_with("atomic_") {
-        let split: Vec<&str> = name.split('_').collect();
+    let (n_tps, inputs, output, unsafety) = if name_str.starts_with("atomic_") {
+        let split: Vec<&str> = name_str.split('_').collect();
         assert!(split.len() >= 2, "Atomic intrinsic in an incorrect format");
 
         //We only care about the operation here
@@ -129,32 +159,30 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
             }
         };
         (n_tps, inputs, output, hir::Unsafety::Unsafe)
-    } else if &name[..] == "abort" {
-        (0, Vec::new(), tcx.types.never, hir::Unsafety::Normal)
-    } else if &name[..] == "unreachable" {
-        (0, Vec::new(), tcx.types.never, hir::Unsafety::Unsafe)
     } else {
-        let unsafety = intrinsic_operation_unsafety(&name[..]);
-        let (n_tps, inputs, output) = match &name[..] {
-            "breakpoint" => (0, Vec::new(), tcx.mk_unit()),
-            "size_of" | "pref_align_of" | "min_align_of" | "variant_count" => {
+        let unsafety = intrinsic_operation_unsafety(intrinsic_name);
+        let (n_tps, inputs, output) = match intrinsic_name {
+            sym::abort => (0, Vec::new(), tcx.types.never),
+            sym::unreachable => (0, Vec::new(), tcx.types.never),
+            sym::breakpoint => (0, Vec::new(), tcx.mk_unit()),
+            sym::size_of | sym::pref_align_of | sym::min_align_of | sym::variant_count => {
                 (1, Vec::new(), tcx.types.usize)
             }
-            "size_of_val" | "min_align_of_val" => {
+            sym::size_of_val | sym::min_align_of_val => {
                 (1, vec![tcx.mk_imm_ptr(param(0))], tcx.types.usize)
             }
-            "rustc_peek" => (1, vec![param(0)], param(0)),
-            "caller_location" => (0, vec![], tcx.caller_location_ty()),
-            "assert_inhabited" | "assert_zero_valid" | "assert_uninit_valid" => {
+            sym::rustc_peek => (1, vec![param(0)], param(0)),
+            sym::caller_location => (0, vec![], tcx.caller_location_ty()),
+            sym::assert_inhabited | sym::assert_zero_valid | sym::assert_uninit_valid => {
                 (1, Vec::new(), tcx.mk_unit())
             }
-            "forget" => (1, vec![param(0)], tcx.mk_unit()),
-            "transmute" => (2, vec![param(0)], param(1)),
-            "move_val_init" => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),
-            "prefetch_read_data"
-            | "prefetch_write_data"
-            | "prefetch_read_instruction"
-            | "prefetch_write_instruction" => (
+            sym::forget => (1, vec![param(0)], tcx.mk_unit()),
+            sym::transmute => (2, vec![param(0)], param(1)),
+            sym::move_val_init => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),
+            sym::prefetch_read_data
+            | sym::prefetch_write_data
+            | sym::prefetch_read_instruction
+            | sym::prefetch_write_instruction => (
                 1,
                 vec![
                     tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
@@ -162,12 +190,12 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
                 ],
                 tcx.mk_unit(),
             ),
-            "drop_in_place" => (1, vec![tcx.mk_mut_ptr(param(0))], tcx.mk_unit()),
-            "needs_drop" => (1, Vec::new(), tcx.types.bool),
+            sym::drop_in_place => (1, vec![tcx.mk_mut_ptr(param(0))], tcx.mk_unit()),
+            sym::needs_drop => (1, Vec::new(), tcx.types.bool),
 
-            "type_name" => (1, Vec::new(), tcx.mk_static_str()),
-            "type_id" => (1, Vec::new(), tcx.types.u64),
-            "offset" | "arith_offset" => (
+            sym::type_name => (1, Vec::new(), tcx.mk_static_str()),
+            sym::type_id => (1, Vec::new(), tcx.types.u64),
+            sym::offset | sym::arith_offset => (
                 1,
                 vec![
                     tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
@@ -175,7 +203,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
                 ],
                 tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
             ),
-            "copy" | "copy_nonoverlapping" => (
+            sym::copy | sym::copy_nonoverlapping => (
                 1,
                 vec![
                     tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
@@ -184,7 +212,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
                 ],
                 tcx.mk_unit(),
             ),
-            "volatile_copy_memory" | "volatile_copy_nonoverlapping_memory" => (
+            sym::volatile_copy_memory | sym::volatile_copy_nonoverlapping_memory => (
                 1,
                 vec![
                     tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }),
@@ -193,7 +221,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
                 ],
                 tcx.mk_unit(),
             ),
-            "write_bytes" | "volatile_set_memory" => (
+            sym::write_bytes | sym::volatile_set_memory => (
                 1,
                 vec![
                     tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }),
@@ -202,93 +230,98 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
                 ],
                 tcx.mk_unit(),
             ),
-            "sqrtf32" => (0, vec![tcx.types.f32], tcx.types.f32),
-            "sqrtf64" => (0, vec![tcx.types.f64], tcx.types.f64),
-            "powif32" => (0, vec![tcx.types.f32, tcx.types.i32], tcx.types.f32),
-            "powif64" => (0, vec![tcx.types.f64, tcx.types.i32], tcx.types.f64),
-            "sinf32" => (0, vec![tcx.types.f32], tcx.types.f32),
-            "sinf64" => (0, vec![tcx.types.f64], tcx.types.f64),
-            "cosf32" => (0, vec![tcx.types.f32], tcx.types.f32),
-            "cosf64" => (0, vec![tcx.types.f64], tcx.types.f64),
-            "powf32" => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
-            "powf64" => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
-            "expf32" => (0, vec![tcx.types.f32], tcx.types.f32),
-            "expf64" => (0, vec![tcx.types.f64], tcx.types.f64),
-            "exp2f32" => (0, vec![tcx.types.f32], tcx.types.f32),
-            "exp2f64" => (0, vec![tcx.types.f64], tcx.types.f64),
-            "logf32" => (0, vec![tcx.types.f32], tcx.types.f32),
-            "logf64" => (0, vec![tcx.types.f64], tcx.types.f64),
-            "log10f32" => (0, vec![tcx.types.f32], tcx.types.f32),
-            "log10f64" => (0, vec![tcx.types.f64], tcx.types.f64),
-            "log2f32" => (0, vec![tcx.types.f32], tcx.types.f32),
-            "log2f64" => (0, vec![tcx.types.f64], tcx.types.f64),
-            "fmaf32" => (0, vec![tcx.types.f32, tcx.types.f32, tcx.types.f32], tcx.types.f32),
-            "fmaf64" => (0, vec![tcx.types.f64, tcx.types.f64, tcx.types.f64], tcx.types.f64),
-            "fabsf32" => (0, vec![tcx.types.f32], tcx.types.f32),
-            "fabsf64" => (0, vec![tcx.types.f64], tcx.types.f64),
-            "minnumf32" => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
-            "minnumf64" => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
-            "maxnumf32" => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
-            "maxnumf64" => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
-            "copysignf32" => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
-            "copysignf64" => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
-            "floorf32" => (0, vec![tcx.types.f32], tcx.types.f32),
-            "floorf64" => (0, vec![tcx.types.f64], tcx.types.f64),
-            "ceilf32" => (0, vec![tcx.types.f32], tcx.types.f32),
-            "ceilf64" => (0, vec![tcx.types.f64], tcx.types.f64),
-            "truncf32" => (0, vec![tcx.types.f32], tcx.types.f32),
-            "truncf64" => (0, vec![tcx.types.f64], tcx.types.f64),
-            "rintf32" => (0, vec![tcx.types.f32], tcx.types.f32),
-            "rintf64" => (0, vec![tcx.types.f64], tcx.types.f64),
-            "nearbyintf32" => (0, vec![tcx.types.f32], tcx.types.f32),
-            "nearbyintf64" => (0, vec![tcx.types.f64], tcx.types.f64),
-            "roundf32" => (0, vec![tcx.types.f32], tcx.types.f32),
-            "roundf64" => (0, vec![tcx.types.f64], tcx.types.f64),
-
-            "volatile_load" | "unaligned_volatile_load" => {
+            sym::sqrtf32 => (0, vec![tcx.types.f32], tcx.types.f32),
+            sym::sqrtf64 => (0, vec![tcx.types.f64], tcx.types.f64),
+            sym::powif32 => (0, vec![tcx.types.f32, tcx.types.i32], tcx.types.f32),
+            sym::powif64 => (0, vec![tcx.types.f64, tcx.types.i32], tcx.types.f64),
+            sym::sinf32 => (0, vec![tcx.types.f32], tcx.types.f32),
+            sym::sinf64 => (0, vec![tcx.types.f64], tcx.types.f64),
+            sym::cosf32 => (0, vec![tcx.types.f32], tcx.types.f32),
+            sym::cosf64 => (0, vec![tcx.types.f64], tcx.types.f64),
+            sym::powf32 => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
+            sym::powf64 => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
+            sym::expf32 => (0, vec![tcx.types.f32], tcx.types.f32),
+            sym::expf64 => (0, vec![tcx.types.f64], tcx.types.f64),
+            sym::exp2f32 => (0, vec![tcx.types.f32], tcx.types.f32),
+            sym::exp2f64 => (0, vec![tcx.types.f64], tcx.types.f64),
+            sym::logf32 => (0, vec![tcx.types.f32], tcx.types.f32),
+            sym::logf64 => (0, vec![tcx.types.f64], tcx.types.f64),
+            sym::log10f32 => (0, vec![tcx.types.f32], tcx.types.f32),
+            sym::log10f64 => (0, vec![tcx.types.f64], tcx.types.f64),
+            sym::log2f32 => (0, vec![tcx.types.f32], tcx.types.f32),
+            sym::log2f64 => (0, vec![tcx.types.f64], tcx.types.f64),
+            sym::fmaf32 => (0, vec![tcx.types.f32, tcx.types.f32, tcx.types.f32], tcx.types.f32),
+            sym::fmaf64 => (0, vec![tcx.types.f64, tcx.types.f64, tcx.types.f64], tcx.types.f64),
+            sym::fabsf32 => (0, vec![tcx.types.f32], tcx.types.f32),
+            sym::fabsf64 => (0, vec![tcx.types.f64], tcx.types.f64),
+            sym::minnumf32 => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
+            sym::minnumf64 => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
+            sym::maxnumf32 => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
+            sym::maxnumf64 => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
+            sym::copysignf32 => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
+            sym::copysignf64 => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
+            sym::floorf32 => (0, vec![tcx.types.f32], tcx.types.f32),
+            sym::floorf64 => (0, vec![tcx.types.f64], tcx.types.f64),
+            sym::ceilf32 => (0, vec![tcx.types.f32], tcx.types.f32),
+            sym::ceilf64 => (0, vec![tcx.types.f64], tcx.types.f64),
+            sym::truncf32 => (0, vec![tcx.types.f32], tcx.types.f32),
+            sym::truncf64 => (0, vec![tcx.types.f64], tcx.types.f64),
+            sym::rintf32 => (0, vec![tcx.types.f32], tcx.types.f32),
+            sym::rintf64 => (0, vec![tcx.types.f64], tcx.types.f64),
+            sym::nearbyintf32 => (0, vec![tcx.types.f32], tcx.types.f32),
+            sym::nearbyintf64 => (0, vec![tcx.types.f64], tcx.types.f64),
+            sym::roundf32 => (0, vec![tcx.types.f32], tcx.types.f32),
+            sym::roundf64 => (0, vec![tcx.types.f64], tcx.types.f64),
+
+            sym::volatile_load | sym::unaligned_volatile_load => {
                 (1, vec![tcx.mk_imm_ptr(param(0))], param(0))
             }
-            "volatile_store" | "unaligned_volatile_store" => {
+            sym::volatile_store | sym::unaligned_volatile_store => {
                 (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit())
             }
 
-            "ctpop" | "ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | "bswap"
-            | "bitreverse" => (1, vec![param(0)], param(0)),
+            sym::ctpop
+            | sym::ctlz
+            | sym::ctlz_nonzero
+            | sym::cttz
+            | sym::cttz_nonzero
+            | sym::bswap
+            | sym::bitreverse => (1, vec![param(0)], param(0)),
 
-            "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" => {
+            sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => {
                 (1, vec![param(0), param(0)], tcx.intern_tup(&[param(0), tcx.types.bool]))
             }
 
-            "ptr_guaranteed_eq" | "ptr_guaranteed_ne" => {
+            sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
                 (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.bool)
             }
 
-            "ptr_offset_from" => {
+            sym::ptr_offset_from => {
                 (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.isize)
             }
-            "unchecked_div" | "unchecked_rem" | "exact_div" => {
+            sym::unchecked_div | sym::unchecked_rem | sym::exact_div => {
                 (1, vec![param(0), param(0)], param(0))
             }
-            "unchecked_shl" | "unchecked_shr" | "rotate_left" | "rotate_right" => {
+            sym::unchecked_shl | sym::unchecked_shr | sym::rotate_left | sym::rotate_right => {
                 (1, vec![param(0), param(0)], param(0))
             }
-            "unchecked_add" | "unchecked_sub" | "unchecked_mul" => {
+            sym::unchecked_add | sym::unchecked_sub | sym::unchecked_mul => {
                 (1, vec![param(0), param(0)], param(0))
             }
-            "wrapping_add" | "wrapping_sub" | "wrapping_mul" => {
+            sym::wrapping_add | sym::wrapping_sub | sym::wrapping_mul => {
                 (1, vec![param(0), param(0)], param(0))
             }
-            "saturating_add" | "saturating_sub" => (1, vec![param(0), param(0)], param(0)),
-            "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => {
+            sym::saturating_add | sym::saturating_sub => (1, vec![param(0), param(0)], param(0)),
+            sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => {
                 (1, vec![param(0), param(0)], param(0))
             }
-            "float_to_int_unchecked" => (2, vec![param(0)], param(1)),
+            sym::float_to_int_unchecked => (2, vec![param(0)], param(1)),
 
-            "assume" => (0, vec![tcx.types.bool], tcx.mk_unit()),
-            "likely" => (0, vec![tcx.types.bool], tcx.types.bool),
-            "unlikely" => (0, vec![tcx.types.bool], tcx.types.bool),
+            sym::assume => (0, vec![tcx.types.bool], tcx.mk_unit()),
+            sym::likely => (0, vec![tcx.types.bool], tcx.types.bool),
+            sym::unlikely => (0, vec![tcx.types.bool], tcx.types.bool),
 
-            "discriminant_value" => {
+            sym::discriminant_value => {
                 let assoc_items =
                     tcx.associated_items(tcx.lang_items().discriminant_kind_trait().unwrap());
                 let discriminant_def_id = assoc_items.in_definition_order().next().unwrap().def_id;
@@ -303,7 +336,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
                 )
             }
 
-            "try" => {
+            kw::Try => {
                 let mut_u8 = tcx.mk_mut_ptr(tcx.types.u8);
                 let try_fn_ty = ty::Binder::bind(tcx.mk_fn_sig(
                     iter::once(mut_u8),
@@ -326,12 +359,12 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
                 )
             }
 
-            "va_start" | "va_end" => match mk_va_list_ty(hir::Mutability::Mut) {
+            sym::va_start | sym::va_end => match mk_va_list_ty(hir::Mutability::Mut) {
                 Some((va_list_ref_ty, _)) => (0, vec![va_list_ref_ty], tcx.mk_unit()),
                 None => bug!("`va_list` language item needed for C-variadic intrinsics"),
             },
 
-            "va_copy" => match mk_va_list_ty(hir::Mutability::Not) {
+            sym::va_copy => match mk_va_list_ty(hir::Mutability::Not) {
                 Some((va_list_ref_ty, va_list_ty)) => {
                     let va_list_ptr_ty = tcx.mk_mut_ptr(va_list_ty);
                     (0, vec![va_list_ptr_ty, va_list_ref_ty], tcx.mk_unit())
@@ -339,28 +372,28 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
                 None => bug!("`va_list` language item needed for C-variadic intrinsics"),
             },
 
-            "va_arg" => match mk_va_list_ty(hir::Mutability::Mut) {
+            sym::va_arg => match mk_va_list_ty(hir::Mutability::Mut) {
                 Some((va_list_ref_ty, _)) => (1, vec![va_list_ref_ty], param(0)),
                 None => bug!("`va_list` language item needed for C-variadic intrinsics"),
             },
 
-            "nontemporal_store" => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),
+            sym::nontemporal_store => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),
 
-            "miri_start_panic" => {
+            sym::miri_start_panic => {
                 // FIXME - the relevant types aren't lang items,
                 // so it's not trivial to check this
                 return;
             }
 
-            "count_code_region" => (0, vec![tcx.types.u32], tcx.mk_unit()),
+            sym::count_code_region => (0, vec![tcx.types.u32], tcx.mk_unit()),
 
-            ref other => {
+            other => {
                 struct_span_err!(
                     tcx.sess,
                     it.span,
                     E0093,
                     "unrecognized intrinsic function: `{}`",
-                    *other
+                    other,
                 )
                 .span_label(it.span, "unrecognized intrinsic")
                 .emit();
@@ -369,7 +402,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
         };
         (n_tps, inputs, output, unsafety)
     };
-    equate_intrinsic_type(tcx, it, n_tps, Abi::RustIntrinsic, unsafety, inputs, output)
+    equate_intrinsic_type(tcx, it, def_id, n_tps, Abi::RustIntrinsic, unsafety, inputs, output)
 }
 
 /// Type-check `extern "platform-intrinsic" { ... }` functions.
@@ -379,6 +412,7 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
         tcx.mk_ty_param(n, name)
     };
 
+    let def_id = tcx.hir().local_def_id(it.hir_id).to_def_id();
     let name = it.ident.as_str();
 
     let (n_tps, inputs, output) = match &*name {
@@ -453,6 +487,7 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
     equate_intrinsic_type(
         tcx,
         it,
+        def_id,
         n_tps,
         Abi::PlatformIntrinsic,
         hir::Unsafety::Unsafe,
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 67bdd04d3715c..b75dac52b93e5 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -608,7 +608,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             ty::Adt(def, _) => bound_spans.push((def_span(def.did), msg)),
                             // Point at the trait object that couldn't satisfy the bound.
                             ty::Dynamic(preds, _) => {
-                                for pred in *preds.skip_binder() {
+                                for pred in preds.skip_binder() {
                                     match pred {
                                         ty::ExistentialPredicate::Trait(tr) => {
                                             bound_spans.push((def_span(tr.def_id), msg.clone()))
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 7c4048ab22302..b617937d6bd54 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2446,7 +2446,7 @@ fn bounds_from_generic_predicates(
 /// Return placeholder code for the given function.
 fn fn_sig_suggestion(
     tcx: TyCtxt<'_>,
-    sig: &ty::FnSig<'_>,
+    sig: ty::FnSig<'_>,
     ident: Ident,
     predicates: ty::GenericPredicates<'_>,
     assoc: &ty::AssocItem,
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index 94a5685a992fe..a1e060b97ad28 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -500,7 +500,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 return false;
             }
             // We're emitting a suggestion, so we can just ignore regions
-            let fn_sig = *self.tcx.fn_sig(def_id).skip_binder();
+            let fn_sig = self.tcx.fn_sig(def_id).skip_binder();
 
             let other_ty = if let FnDef(def_id, _) = other_ty.kind {
                 if !self.tcx.has_typeck_tables(def_id) {
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index a45a44a6801e8..3b203dd222afb 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -216,7 +216,7 @@ fn check_object_overlap<'tcx>(
         let component_def_ids = data.iter().flat_map(|predicate| {
             match predicate.skip_binder() {
                 ty::ExistentialPredicate::Trait(tr) => Some(tr.def_id),
-                ty::ExistentialPredicate::AutoTrait(def_id) => Some(*def_id),
+                ty::ExistentialPredicate::AutoTrait(def_id) => Some(def_id),
                 // An associated type projection necessarily comes with
                 // an additional `Trait` requirement.
                 ty::ExistentialPredicate::Projection(..) => None,
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index b486e3d3536c9..cc491c527db0b 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -2063,7 +2063,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
     ident: Ident,
 ) -> ty::PolyFnSig<'tcx> {
     let unsafety = if abi == abi::Abi::RustIntrinsic {
-        intrinsic_operation_unsafety(&tcx.item_name(def_id).as_str())
+        intrinsic_operation_unsafety(tcx.item_name(def_id))
     } else {
         hir::Unsafety::Unsafe
     };
@@ -2102,11 +2102,11 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
                     .emit();
             }
         };
-        for (input, ty) in decl.inputs.iter().zip(*fty.inputs().skip_binder()) {
+        for (input, ty) in decl.inputs.iter().zip(fty.inputs().skip_binder()) {
             check(&input, ty)
         }
         if let hir::FnRetTy::Return(ref ty) = decl.output {
-            check(&ty, *fty.output().skip_binder())
+            check(&ty, fty.output().skip_binder())
         }
     }
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 73fe87b05d477..bfe8464347d29 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -347,7 +347,7 @@ impl Clean<GenericBound> for (ty::PolyTraitRef<'_>, &[TypeBinding]) {
 
         GenericBound::TraitBound(
             PolyTrait {
-                trait_: (*poly_trait_ref.skip_binder(), bounds).clean(cx),
+                trait_: (poly_trait_ref.skip_binder(), bounds).clean(cx),
                 generic_params: late_bound_regions,
             },
             hir::TraitBoundModifier::None,
@@ -549,7 +549,7 @@ impl<'tcx> Clean<Option<WherePredicate>> for ty::PolyOutlivesPredicate<Ty<'tcx>,
 
 impl<'tcx> Clean<WherePredicate> for ty::PolyProjectionPredicate<'tcx> {
     fn clean(&self, cx: &DocContext<'_>) -> WherePredicate {
-        let ty::ProjectionPredicate { projection_ty, ty } = *self.skip_binder();
+        let ty::ProjectionPredicate { projection_ty, ty } = self.skip_binder();
         WherePredicate::EqPredicate { lhs: projection_ty.clean(cx), rhs: ty.clean(cx) }
     }
 }
@@ -1177,7 +1177,7 @@ impl Clean<Item> for ty::AssocItem {
                         ty::ImplContainer(def_id) => cx.tcx.type_of(def_id),
                         ty::TraitContainer(_) => cx.tcx.types.self_param,
                     };
-                    let self_arg_ty = *sig.input(0).skip_binder();
+                    let self_arg_ty = sig.input(0).skip_binder();
                     if self_arg_ty == self_ty {
                         decl.inputs.values[0].type_ = Generic(String::from("Self"));
                     } else if let ty::Ref(_, ty, _) = self_arg_ty.kind {
@@ -1679,7 +1679,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                                 if let ty::PredicateKind::Projection(proj) = pred.kind() {
                                     let proj = proj.skip_binder();
                                     if proj.projection_ty.trait_ref(cx.tcx)
-                                        == *trait_ref.skip_binder()
+                                        == trait_ref.skip_binder()
                                     {
                                         Some(TypeBinding {
                                             name: cx
diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs
index d972cf6db18cf..0b3386c05d54b 100644
--- a/src/libstd/keyword_docs.rs
+++ b/src/libstd/keyword_docs.rs
@@ -1281,11 +1281,84 @@ mod self_upper_keyword {}
 
 #[doc(keyword = "static")]
 //
-/// A place that is valid for the duration of a program.
+/// A static item is a value which is valid for the entire duration of your
+/// program (a `'static` lifetime).
 ///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// On the surface, `static` items seem very similar to [`const`]s: both contain
+/// a value, both require type annotations and both can only be initialized with
+/// constant functions and values. However, `static`s are notably different in
+/// that they represent a location in memory. That means that you can have
+/// references to `static` items and potentially even modify them, making them
+/// essentially global variables.
 ///
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+/// Static items do not call [`drop`] at the end of the program.
+///
+/// There are two types of `static` items: those declared in association with
+/// the [`mut`] keyword and those without.
+///
+/// Static items cannot be moved:
+///
+/// ```rust,compile_fail,E0507
+/// static VEC: Vec<u32> = vec![];
+///
+/// fn move_vec(v: Vec<u32>) -> Vec<u32> {
+///     v
+/// }
+///
+/// // This line causes an error
+/// move_vec(VEC);
+/// ```
+///
+/// # Simple `static`s
+///
+/// Accessing non-[`mut`] `static` items is considered safe, but some
+/// restrictions apply. Most notably, the type of a `static` value needs to
+/// implement the [`Sync`] trait, ruling out interior mutability containers
+/// like [`RefCell`]. See the [Reference] for more information.
+///
+/// ```rust
+/// static FOO: [i32; 5] = [1, 2, 3, 4, 5];
+///
+/// let r1 = &FOO as *const _;
+/// let r2 = &FOO as *const _;
+/// // With a strictly read-only static, references will have the same adress
+/// assert_eq!(r1, r2);
+/// // A static item can be used just like a variable in many cases
+/// println!("{:?}", FOO);
+/// ```
+///
+/// # Mutable `static`s
+///
+/// If a `static` item is declared with the [`mut`] keyword, then it is allowed
+/// to be modified by the program. However, accessing mutable `static`s can
+/// cause undefined behavior in a number of ways, for example due to data races
+/// in a multithreaded context. As such, all accesses to mutable `static`s
+/// require an [`unsafe`] block.
+///
+/// Despite their unsafety, mutable `static`s are necessary in many contexts:
+/// they can be used to represent global state shared by the whole program or in
+/// [`extern`] blocks to bind to variables from C libraries.
+///
+/// In an [`extern`] block:
+///
+/// ```rust,no_run
+/// # #![allow(dead_code)]
+/// extern "C" {
+///     static mut ERROR_MESSAGE: *mut std::os::raw::c_char;
+/// }
+/// ```
+///
+/// Mutable `static`s, just like simple `static`s, have some restrictions that
+/// apply to them. See the [Reference] for more information.
+///
+/// [`const`]: keyword.const.html
+/// [`extern`]: keyword.extern.html
+/// [`mut`]: keyword.mut.html
+/// [`unsafe`]: keyword.unsafe.html
+/// [`drop`]: mem/fn.drop.html
+/// [`Sync`]: marker/trait.Sync.html
+/// [`RefCell`]: cell/struct.RefCell.html
+/// [Reference]: ../reference/items/static-items.html
 mod static_keyword {}
 
 #[doc(keyword = "struct")]
@@ -1463,9 +1536,44 @@ mod true_keyword {}
 //
 /// Define an alias for an existing type.
 ///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// The syntax is `type Name = ExistingType;`.
 ///
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+/// # Examples
+///
+/// `type` does **not** create a new type:
+///
+/// ```rust
+/// type Meters = u32;
+/// type Kilograms = u32;
+///
+/// let m: Meters = 3;
+/// let k: Kilograms = 3;
+///
+/// assert_eq!(m, k);
+/// ```
+///
+/// In traits, `type` is used to declare an [associated type]:
+///
+/// ```rust
+/// trait Iterator {
+///     // associated type declaration
+///     type Item;
+///     fn next(&mut self) -> Option<Self::Item>;
+/// }
+///
+/// struct Once<T>(Option<T>);
+///
+/// impl<T> Iterator for Once<T> {
+///     // associated type definition
+///     type Item = T;
+///     fn next(&mut self) -> Option<Self::Item> {
+///         self.0.take()
+///     }
+/// }
+/// ```
+///
+/// [`trait`]: keyword.trait.html
+/// [associated type]: ../reference/items/associated-items.html#associated-types
 mod type_keyword {}
 
 #[doc(keyword = "unsafe")]
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index ef699ede2a140..372038df54f2e 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -316,7 +316,7 @@
 #![feature(toowned_clone_into)]
 #![feature(total_cmp)]
 #![feature(trace_macros)]
-#![feature(track_caller)]
+#![cfg_attr(bootstrap, feature(track_caller))]
 #![feature(try_reserve)]
 #![feature(unboxed_closures)]
 #![feature(untagged_unions)]
diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs
index 640c9f3636d4b..193ab5b47ef13 100644
--- a/src/libstd/sys/windows/mod.rs
+++ b/src/libstd/sys/windows/mod.rs
@@ -61,6 +61,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
         c::ERROR_FILE_NOT_FOUND => return ErrorKind::NotFound,
         c::ERROR_PATH_NOT_FOUND => return ErrorKind::NotFound,
         c::ERROR_NO_DATA => return ErrorKind::BrokenPipe,
+        c::ERROR_INVALID_PARAMETER => return ErrorKind::InvalidInput,
         c::ERROR_SEM_TIMEOUT
         | c::WAIT_TIMEOUT
         | c::ERROR_DRIVER_CANCEL_TIMEOUT
diff --git a/src/test/ui/anon-params/anon-params-denied-2018.stderr b/src/test/ui/anon-params/anon-params-denied-2018.stderr
index e7a806a846820..840294db0830a 100644
--- a/src/test/ui/anon-params/anon-params-denied-2018.stderr
+++ b/src/test/ui/anon-params/anon-params-denied-2018.stderr
@@ -9,7 +9,7 @@ help: if this is a `self` type, give it a parameter name
    |
 LL |     fn foo(self: i32);
    |            ^^^^^^^^^
-help: if this was a parameter name, give it a type
+help: if this is a parameter name, give it a type
    |
 LL |     fn foo(i32: TypeName);
    |            ^^^^^^^^^^^^^
@@ -29,7 +29,7 @@ help: if this is a `self` type, give it a parameter name
    |
 LL |     fn bar_with_default_impl(self: String, String) {}
    |                              ^^^^^^^^^^^^
-help: if this was a parameter name, give it a type
+help: if this is a parameter name, give it a type
    |
 LL |     fn bar_with_default_impl(String: TypeName, String) {}
    |                              ^^^^^^^^^^^^^^^^
@@ -45,7 +45,7 @@ LL |     fn bar_with_default_impl(String, String) {}
    |                                            ^ expected one of `:`, `@`, or `|`
    |
    = note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
-help: if this was a parameter name, give it a type
+help: if this is a parameter name, give it a type
    |
 LL |     fn bar_with_default_impl(String, String: TypeName) {}
    |                                      ^^^^^^^^^^^^^^^^
@@ -61,7 +61,7 @@ LL |     fn baz(a:usize, b, c: usize) -> usize {
    |                      ^ expected one of `:`, `@`, or `|`
    |
    = note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
-help: if this was a parameter name, give it a type
+help: if this is a parameter name, give it a type
    |
 LL |     fn baz(a:usize, b: TypeName, c: usize) -> usize {
    |                     ^^^^^^^^^^^
diff --git a/src/test/ui/asm/sym.rs b/src/test/ui/asm/sym.rs
index 8cff16aa75f69..9931697e4129c 100644
--- a/src/test/ui/asm/sym.rs
+++ b/src/test/ui/asm/sym.rs
@@ -3,7 +3,7 @@
 // only-linux
 // run-pass
 
-#![feature(asm, track_caller, thread_local)]
+#![feature(asm, thread_local)]
 
 extern "C" fn f1() -> i32 {
     111
diff --git a/src/test/ui/feature-gates/feature-gate-track_caller.rs b/src/test/ui/feature-gates/feature-gate-track_caller.rs
deleted file mode 100644
index 5865cf0a4f754..0000000000000
--- a/src/test/ui/feature-gates/feature-gate-track_caller.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-#[track_caller]
-fn f() {}
-//~^^ ERROR the `#[track_caller]` attribute is an experimental feature
-
-fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-track_caller.stderr b/src/test/ui/feature-gates/feature-gate-track_caller.stderr
deleted file mode 100644
index 8ceab501617ee..0000000000000
--- a/src/test/ui/feature-gates/feature-gate-track_caller.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: the `#[track_caller]` attribute is an experimental feature
-  --> $DIR/feature-gate-track_caller.rs:1:1
-   |
-LL | #[track_caller]
-   | ^^^^^^^^^^^^^^^
-   |
-   = note: see issue #47809 <https://github.com/rust-lang/rust/issues/47809> for more information
-   = help: add `#![feature(track_caller)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/macros/issue-68060.rs b/src/test/ui/macros/issue-68060.rs
index bc70f8ffec2b2..8772e98b6e9bb 100644
--- a/src/test/ui/macros/issue-68060.rs
+++ b/src/test/ui/macros/issue-68060.rs
@@ -1,5 +1,3 @@
-#![feature(track_caller)]
-
 fn main() {
     (0..)
         .map(
diff --git a/src/test/ui/macros/issue-68060.stderr b/src/test/ui/macros/issue-68060.stderr
index 22187c4a4098a..b9b2f946c5967 100644
--- a/src/test/ui/macros/issue-68060.stderr
+++ b/src/test/ui/macros/issue-68060.stderr
@@ -1,5 +1,5 @@
 error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions
-  --> $DIR/issue-68060.rs:6:13
+  --> $DIR/issue-68060.rs:4:13
    |
 LL |             #[target_feature(enable = "")]
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -11,13 +11,13 @@ LL |             |_| (),
    = help: add `#![feature(target_feature_11)]` to the crate attributes to enable
 
 error: the feature named `` is not valid for this target
-  --> $DIR/issue-68060.rs:6:30
+  --> $DIR/issue-68060.rs:4:30
    |
 LL |             #[target_feature(enable = "")]
    |                              ^^^^^^^^^^^ `` is not valid for this target
 
 error[E0737]: `#[track_caller]` requires Rust ABI
-  --> $DIR/issue-68060.rs:9:13
+  --> $DIR/issue-68060.rs:7:13
    |
 LL |             #[track_caller]
    |             ^^^^^^^^^^^^^^^
diff --git a/src/test/ui/mir-dataflow/def-inits-1.rs b/src/test/ui/mir-dataflow/def-inits-1.rs
index 91d41e9b5794e..30460824a1678 100644
--- a/src/test/ui/mir-dataflow/def-inits-1.rs
+++ b/src/test/ui/mir-dataflow/def-inits-1.rs
@@ -11,13 +11,13 @@ struct S(i32);
 fn foo(test: bool, x: &mut S, y: S, mut z: S) -> S {
     let ret;
     // `ret` starts off uninitialized
-    unsafe { rustc_peek(&ret); }  //~ ERROR rustc_peek: bit not set
+    rustc_peek(&ret);  //~ ERROR rustc_peek: bit not set
 
     // All function formal parameters start off initialized.
 
-    unsafe { rustc_peek(&x) };
-    unsafe { rustc_peek(&y) };
-    unsafe { rustc_peek(&z) };
+    rustc_peek(&x);
+    rustc_peek(&y);
+    rustc_peek(&z);
 
     ret = if test {
         ::std::mem::replace(x, y)
@@ -27,21 +27,21 @@ fn foo(test: bool, x: &mut S, y: S, mut z: S) -> S {
     };
 
     // `z` may be uninitialized here.
-    unsafe { rustc_peek(&z); } //~ ERROR rustc_peek: bit not set
+    rustc_peek(&z); //~ ERROR rustc_peek: bit not set
 
     // `y` is definitely uninitialized here.
-    unsafe { rustc_peek(&y); } //~ ERROR rustc_peek: bit not set
+    rustc_peek(&y); //~ ERROR rustc_peek: bit not set
 
     // `x` is still (definitely) initialized (replace above is a reborrow).
-    unsafe { rustc_peek(&x); }
+    rustc_peek(&x);
 
     ::std::mem::drop(x);
 
     // `x` is *definitely* uninitialized here
-    unsafe { rustc_peek(&x); } //~ ERROR rustc_peek: bit not set
+    rustc_peek(&x); //~ ERROR rustc_peek: bit not set
 
     // `ret` is now definitely initialized (via `if` above).
-    unsafe { rustc_peek(&ret); }
+    rustc_peek(&ret);
 
     ret
 }
diff --git a/src/test/ui/mir-dataflow/def-inits-1.stderr b/src/test/ui/mir-dataflow/def-inits-1.stderr
index 48d8450489488..e2bddb54d9ba8 100644
--- a/src/test/ui/mir-dataflow/def-inits-1.stderr
+++ b/src/test/ui/mir-dataflow/def-inits-1.stderr
@@ -1,26 +1,26 @@
 error: rustc_peek: bit not set
-  --> $DIR/def-inits-1.rs:14:14
+  --> $DIR/def-inits-1.rs:14:5
    |
-LL |     unsafe { rustc_peek(&ret); }
-   |              ^^^^^^^^^^^^^^^^
+LL |     rustc_peek(&ret);
+   |     ^^^^^^^^^^^^^^^^
 
 error: rustc_peek: bit not set
-  --> $DIR/def-inits-1.rs:30:14
+  --> $DIR/def-inits-1.rs:30:5
    |
-LL |     unsafe { rustc_peek(&z); }
-   |              ^^^^^^^^^^^^^^
+LL |     rustc_peek(&z);
+   |     ^^^^^^^^^^^^^^
 
 error: rustc_peek: bit not set
-  --> $DIR/def-inits-1.rs:33:14
+  --> $DIR/def-inits-1.rs:33:5
    |
-LL |     unsafe { rustc_peek(&y); }
-   |              ^^^^^^^^^^^^^^
+LL |     rustc_peek(&y);
+   |     ^^^^^^^^^^^^^^
 
 error: rustc_peek: bit not set
-  --> $DIR/def-inits-1.rs:41:14
+  --> $DIR/def-inits-1.rs:41:5
    |
-LL |     unsafe { rustc_peek(&x); }
-   |              ^^^^^^^^^^^^^^
+LL |     rustc_peek(&x);
+   |     ^^^^^^^^^^^^^^
 
 error: stop_after_dataflow ended compilation
 
diff --git a/src/test/ui/mir-dataflow/indirect-mutation-offset.rs b/src/test/ui/mir-dataflow/indirect-mutation-offset.rs
index caa307e269fe7..374a9f75a134b 100644
--- a/src/test/ui/mir-dataflow/indirect-mutation-offset.rs
+++ b/src/test/ui/mir-dataflow/indirect-mutation-offset.rs
@@ -38,7 +38,7 @@ const BOO: i32 = {
 
     *rmut_cell = 42;  // Mutates `x` indirectly even though `x` is not marked indirectly mutable!!!
     let val = *rmut_cell;
-    unsafe { rustc_peek(x) }; //~ ERROR rustc_peek: bit not set
+    rustc_peek(x); //~ ERROR rustc_peek: bit not set
 
     val
 };
diff --git a/src/test/ui/mir-dataflow/indirect-mutation-offset.stderr b/src/test/ui/mir-dataflow/indirect-mutation-offset.stderr
index 8d3548ececdd9..1d5287c15ab79 100644
--- a/src/test/ui/mir-dataflow/indirect-mutation-offset.stderr
+++ b/src/test/ui/mir-dataflow/indirect-mutation-offset.stderr
@@ -1,8 +1,8 @@
 error: rustc_peek: bit not set
-  --> $DIR/indirect-mutation-offset.rs:41:14
+  --> $DIR/indirect-mutation-offset.rs:41:5
    |
-LL |     unsafe { rustc_peek(x) };
-   |              ^^^^^^^^^^^^^
+LL |     rustc_peek(x);
+   |     ^^^^^^^^^^^^^
 
 error: stop_after_dataflow ended compilation
 
diff --git a/src/test/ui/mir-dataflow/inits-1.rs b/src/test/ui/mir-dataflow/inits-1.rs
index 4a4786a2a7378..8fb1d4bc736d6 100644
--- a/src/test/ui/mir-dataflow/inits-1.rs
+++ b/src/test/ui/mir-dataflow/inits-1.rs
@@ -11,13 +11,13 @@ struct S(i32);
 fn foo(test: bool, x: &mut S, y: S, mut z: S) -> S {
     let ret;
     // `ret` starts off uninitialized, so we get an error report here.
-    unsafe { rustc_peek(&ret); }  //~ ERROR rustc_peek: bit not set
+    rustc_peek(&ret);  //~ ERROR rustc_peek: bit not set
 
     // All function formal parameters start off initialized.
 
-    unsafe { rustc_peek(&x) };
-    unsafe { rustc_peek(&y) };
-    unsafe { rustc_peek(&z) };
+    rustc_peek(&x);
+    rustc_peek(&y);
+    rustc_peek(&z);
 
     ret = if test {
         ::std::mem::replace(x, y)
@@ -28,21 +28,21 @@ fn foo(test: bool, x: &mut S, y: S, mut z: S) -> S {
 
 
     // `z` may be initialized here.
-    unsafe { rustc_peek(&z); }
+    rustc_peek(&z);
 
     // `y` is definitely uninitialized here.
-    unsafe { rustc_peek(&y); }  //~ ERROR rustc_peek: bit not set
+    rustc_peek(&y);  //~ ERROR rustc_peek: bit not set
 
     // `x` is still (definitely) initialized (replace above is a reborrow).
-    unsafe { rustc_peek(&x); }
+    rustc_peek(&x);
 
     ::std::mem::drop(x);
 
     // `x` is *definitely* uninitialized here
-    unsafe { rustc_peek(&x); } //~ ERROR rustc_peek: bit not set
+    rustc_peek(&x); //~ ERROR rustc_peek: bit not set
 
     // `ret` is now definitely initialized (via `if` above).
-    unsafe { rustc_peek(&ret); }
+    rustc_peek(&ret);
 
     ret
 }
diff --git a/src/test/ui/mir-dataflow/inits-1.stderr b/src/test/ui/mir-dataflow/inits-1.stderr
index 23d0679cb1ac1..7a00a70af6f84 100644
--- a/src/test/ui/mir-dataflow/inits-1.stderr
+++ b/src/test/ui/mir-dataflow/inits-1.stderr
@@ -1,20 +1,20 @@
 error: rustc_peek: bit not set
-  --> $DIR/inits-1.rs:14:14
+  --> $DIR/inits-1.rs:14:5
    |
-LL |     unsafe { rustc_peek(&ret); }
-   |              ^^^^^^^^^^^^^^^^
+LL |     rustc_peek(&ret);
+   |     ^^^^^^^^^^^^^^^^
 
 error: rustc_peek: bit not set
-  --> $DIR/inits-1.rs:34:14
+  --> $DIR/inits-1.rs:34:5
    |
-LL |     unsafe { rustc_peek(&y); }
-   |              ^^^^^^^^^^^^^^
+LL |     rustc_peek(&y);
+   |     ^^^^^^^^^^^^^^
 
 error: rustc_peek: bit not set
-  --> $DIR/inits-1.rs:42:14
+  --> $DIR/inits-1.rs:42:5
    |
-LL |     unsafe { rustc_peek(&x); }
-   |              ^^^^^^^^^^^^^^
+LL |     rustc_peek(&x);
+   |     ^^^^^^^^^^^^^^
 
 error: stop_after_dataflow ended compilation
 
diff --git a/src/test/ui/mir-dataflow/liveness-ptr.rs b/src/test/ui/mir-dataflow/liveness-ptr.rs
index 34097d7526a6e..786da523a3391 100644
--- a/src/test/ui/mir-dataflow/liveness-ptr.rs
+++ b/src/test/ui/mir-dataflow/liveness-ptr.rs
@@ -10,17 +10,17 @@ fn foo() -> i32 {
     x = 0;
 
     // `x` is live here since it is used in the next statement...
-    unsafe { rustc_peek(x); }
+    rustc_peek(x);
 
     p = &x;
 
     // ... but not here, even while it can be accessed through `p`.
-    unsafe { rustc_peek(x); } //~ ERROR rustc_peek: bit not set
+    rustc_peek(x); //~ ERROR rustc_peek: bit not set
     let tmp = unsafe { *p };
 
     x = tmp + 1;
 
-    unsafe { rustc_peek(x); }
+    rustc_peek(x);
 
     x
 }
diff --git a/src/test/ui/mir-dataflow/liveness-ptr.stderr b/src/test/ui/mir-dataflow/liveness-ptr.stderr
index 3397d0c5a121d..858cdbac3d312 100644
--- a/src/test/ui/mir-dataflow/liveness-ptr.stderr
+++ b/src/test/ui/mir-dataflow/liveness-ptr.stderr
@@ -1,8 +1,8 @@
 error: rustc_peek: bit not set
-  --> $DIR/liveness-ptr.rs:18:14
+  --> $DIR/liveness-ptr.rs:18:5
    |
-LL |     unsafe { rustc_peek(x); }
-   |              ^^^^^^^^^^^^^
+LL |     rustc_peek(x);
+   |     ^^^^^^^^^^^^^
 
 error: stop_after_dataflow ended compilation
 
diff --git a/src/test/ui/mir-dataflow/uninits-1.rs b/src/test/ui/mir-dataflow/uninits-1.rs
index 66b3f458a5159..c2b4284a7b4f8 100644
--- a/src/test/ui/mir-dataflow/uninits-1.rs
+++ b/src/test/ui/mir-dataflow/uninits-1.rs
@@ -11,13 +11,13 @@ struct S(i32);
 fn foo(test: bool, x: &mut S, y: S, mut z: S) -> S {
     let ret;
     // `ret` starts off uninitialized
-    unsafe { rustc_peek(&ret); }
+    rustc_peek(&ret);
 
     // All function formal parameters start off initialized.
 
-    unsafe { rustc_peek(&x) }; //~ ERROR rustc_peek: bit not set
-    unsafe { rustc_peek(&y) }; //~ ERROR rustc_peek: bit not set
-    unsafe { rustc_peek(&z) }; //~ ERROR rustc_peek: bit not set
+    rustc_peek(&x); //~ ERROR rustc_peek: bit not set
+    rustc_peek(&y); //~ ERROR rustc_peek: bit not set
+    rustc_peek(&z); //~ ERROR rustc_peek: bit not set
 
     ret = if test {
         ::std::mem::replace(x, y)
@@ -27,21 +27,21 @@ fn foo(test: bool, x: &mut S, y: S, mut z: S) -> S {
     };
 
     // `z` may be uninitialized here.
-    unsafe { rustc_peek(&z); }
+    rustc_peek(&z);
 
     // `y` is definitely uninitialized here.
-    unsafe { rustc_peek(&y); }
+    rustc_peek(&y);
 
     // `x` is still (definitely) initialized (replace above is a reborrow).
-    unsafe { rustc_peek(&x); } //~ ERROR rustc_peek: bit not set
+    rustc_peek(&x); //~ ERROR rustc_peek: bit not set
 
     ::std::mem::drop(x);
 
     // `x` is *definitely* uninitialized here
-    unsafe { rustc_peek(&x); }
+    rustc_peek(&x);
 
     // `ret` is now definitely initialized (via `if` above).
-    unsafe { rustc_peek(&ret); } //~ ERROR rustc_peek: bit not set
+    rustc_peek(&ret); //~ ERROR rustc_peek: bit not set
 
     ret
 }
diff --git a/src/test/ui/mir-dataflow/uninits-1.stderr b/src/test/ui/mir-dataflow/uninits-1.stderr
index 5f6dbde212d0a..c52f5ac7bd9b6 100644
--- a/src/test/ui/mir-dataflow/uninits-1.stderr
+++ b/src/test/ui/mir-dataflow/uninits-1.stderr
@@ -1,32 +1,32 @@
 error: rustc_peek: bit not set
-  --> $DIR/uninits-1.rs:18:14
+  --> $DIR/uninits-1.rs:18:5
    |
-LL |     unsafe { rustc_peek(&x) };
-   |              ^^^^^^^^^^^^^^
+LL |     rustc_peek(&x);
+   |     ^^^^^^^^^^^^^^
 
 error: rustc_peek: bit not set
-  --> $DIR/uninits-1.rs:19:14
+  --> $DIR/uninits-1.rs:19:5
    |
-LL |     unsafe { rustc_peek(&y) };
-   |              ^^^^^^^^^^^^^^
+LL |     rustc_peek(&y);
+   |     ^^^^^^^^^^^^^^
 
 error: rustc_peek: bit not set
-  --> $DIR/uninits-1.rs:20:14
+  --> $DIR/uninits-1.rs:20:5
    |
-LL |     unsafe { rustc_peek(&z) };
-   |              ^^^^^^^^^^^^^^
+LL |     rustc_peek(&z);
+   |     ^^^^^^^^^^^^^^
 
 error: rustc_peek: bit not set
-  --> $DIR/uninits-1.rs:36:14
+  --> $DIR/uninits-1.rs:36:5
    |
-LL |     unsafe { rustc_peek(&x); }
-   |              ^^^^^^^^^^^^^^
+LL |     rustc_peek(&x);
+   |     ^^^^^^^^^^^^^^
 
 error: rustc_peek: bit not set
-  --> $DIR/uninits-1.rs:44:14
+  --> $DIR/uninits-1.rs:44:5
    |
-LL |     unsafe { rustc_peek(&ret); }
-   |              ^^^^^^^^^^^^^^^^
+LL |     rustc_peek(&ret);
+   |     ^^^^^^^^^^^^^^^^
 
 error: stop_after_dataflow ended compilation
 
diff --git a/src/test/ui/mir-dataflow/uninits-2.rs b/src/test/ui/mir-dataflow/uninits-2.rs
index 2ccf1c7f9d6c6..c584ee74afb48 100644
--- a/src/test/ui/mir-dataflow/uninits-2.rs
+++ b/src/test/ui/mir-dataflow/uninits-2.rs
@@ -11,12 +11,12 @@ struct S(i32);
 fn foo(x: &mut S) {
     // `x` is initialized here, so maybe-uninit bit is 0.
 
-    unsafe { rustc_peek(&x) }; //~ ERROR rustc_peek: bit not set
+    rustc_peek(&x); //~ ERROR rustc_peek: bit not set
 
     ::std::mem::drop(x);
 
     // `x` definitely uninitialized here, so maybe-uninit bit is 1.
-    unsafe { rustc_peek(&x) };
+    rustc_peek(&x);
 }
 fn main() {
     foo(&mut S(13));
diff --git a/src/test/ui/mir-dataflow/uninits-2.stderr b/src/test/ui/mir-dataflow/uninits-2.stderr
index dcb61371994db..0ef954e35a4d8 100644
--- a/src/test/ui/mir-dataflow/uninits-2.stderr
+++ b/src/test/ui/mir-dataflow/uninits-2.stderr
@@ -1,8 +1,8 @@
 error: rustc_peek: bit not set
-  --> $DIR/uninits-2.rs:14:14
+  --> $DIR/uninits-2.rs:14:5
    |
-LL |     unsafe { rustc_peek(&x) };
-   |              ^^^^^^^^^^^^^^
+LL |     rustc_peek(&x);
+   |     ^^^^^^^^^^^^^^
 
 error: stop_after_dataflow ended compilation
 
diff --git a/src/test/ui/numbers-arithmetic/saturating-float-casts.rs b/src/test/ui/numbers-arithmetic/saturating-float-casts.rs
index e6d0c94a02fac..825a11972aeeb 100644
--- a/src/test/ui/numbers-arithmetic/saturating-float-casts.rs
+++ b/src/test/ui/numbers-arithmetic/saturating-float-casts.rs
@@ -9,7 +9,6 @@
 // merged.
 
 #![feature(test, stmt_expr_attributes)]
-#![feature(track_caller)]
 #![deny(overflowing_literals)]
 extern crate test;
 
diff --git a/src/test/ui/parser/inverted-parameters.rs b/src/test/ui/parser/inverted-parameters.rs
index 6f19ee9c7dc0d..5c4272504e061 100644
--- a/src/test/ui/parser/inverted-parameters.rs
+++ b/src/test/ui/parser/inverted-parameters.rs
@@ -20,7 +20,7 @@ fn pattern((i32, i32) (a, b)) {}
 
 fn fizz(i32) {}
 //~^ ERROR expected one of `:`, `@`
-//~| HELP if this was a parameter name, give it a type
+//~| HELP if this is a parameter name, give it a type
 //~| HELP if this is a `self` type, give it a parameter name
 //~| HELP if this is a type, explicitly ignore the parameter name
 
diff --git a/src/test/ui/parser/inverted-parameters.stderr b/src/test/ui/parser/inverted-parameters.stderr
index 043ff65f74e1a..ae180af93e373 100644
--- a/src/test/ui/parser/inverted-parameters.stderr
+++ b/src/test/ui/parser/inverted-parameters.stderr
@@ -39,7 +39,7 @@ help: if this is a `self` type, give it a parameter name
    |
 LL | fn fizz(self: i32) {}
    |         ^^^^^^^^^
-help: if this was a parameter name, give it a type
+help: if this is a parameter name, give it a type
    |
 LL | fn fizz(i32: TypeName) {}
    |         ^^^^^^^^^^^^^
diff --git a/src/test/ui/parser/omitted-arg-in-item-fn.stderr b/src/test/ui/parser/omitted-arg-in-item-fn.stderr
index 9f138bf84ce19..bc3329dcbc23d 100644
--- a/src/test/ui/parser/omitted-arg-in-item-fn.stderr
+++ b/src/test/ui/parser/omitted-arg-in-item-fn.stderr
@@ -9,7 +9,7 @@ help: if this is a `self` type, give it a parameter name
    |
 LL | fn foo(self: x) {
    |        ^^^^^^^
-help: if this was a parameter name, give it a type
+help: if this is a parameter name, give it a type
    |
 LL | fn foo(x: TypeName) {
    |        ^^^^^^^^^^^
diff --git a/src/test/ui/parser/recover-field-extra-angle-brackets.rs b/src/test/ui/parser/recover-field-extra-angle-brackets.rs
new file mode 100644
index 0000000000000..5e0e00bcb5e8d
--- /dev/null
+++ b/src/test/ui/parser/recover-field-extra-angle-brackets.rs
@@ -0,0 +1,14 @@
+// Tests that we recover from extra trailing angle brackets
+// in a struct field
+
+struct BadStruct {
+    first: Vec<u8>>, //~ ERROR unmatched angle bracket
+    second: bool
+}
+
+fn bar(val: BadStruct) {
+    val.first;
+    val.second;
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/recover-field-extra-angle-brackets.stderr b/src/test/ui/parser/recover-field-extra-angle-brackets.stderr
new file mode 100644
index 0000000000000..318e55f6e99ac
--- /dev/null
+++ b/src/test/ui/parser/recover-field-extra-angle-brackets.stderr
@@ -0,0 +1,8 @@
+error: unmatched angle bracket
+  --> $DIR/recover-field-extra-angle-brackets.rs:5:19
+   |
+LL |     first: Vec<u8>>,
+   |                   ^ help: remove extra angle bracket
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/rfc-2091-track-caller/call-chain.rs b/src/test/ui/rfc-2091-track-caller/call-chain.rs
index 3f1c8f7abe8b8..fefb84de729fe 100644
--- a/src/test/ui/rfc-2091-track-caller/call-chain.rs
+++ b/src/test/ui/rfc-2091-track-caller/call-chain.rs
@@ -1,7 +1,5 @@
 // run-pass
 
-#![feature(track_caller)]
-
 use std::panic::Location;
 
 struct Foo;
diff --git a/src/test/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs b/src/test/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs
index edf9ba2c41a15..05240908917bc 100644
--- a/src/test/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs
+++ b/src/test/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs
@@ -6,7 +6,7 @@
 // run-pass
 // compile-flags: -Z unleash-the-miri-inside-of-you
 
-#![feature(core_intrinsics, const_caller_location, track_caller, const_fn)]
+#![feature(core_intrinsics, const_caller_location, const_fn)]
 
 type L = &'static std::panic::Location<'static>;
 
diff --git a/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs b/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs
index 090e912c1d0ba..f244b74e391ff 100644
--- a/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs
+++ b/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs
@@ -1,7 +1,5 @@
 // run-pass
 
-#![feature(track_caller)]
-
 #[inline(never)]
 #[track_caller]
 fn codegen_caller_loc() -> &'static core::panic::Location<'static> {
@@ -15,13 +13,13 @@ macro_rules! caller_location_from_macro {
 fn main() {
     let loc = codegen_caller_loc();
     assert_eq!(loc.file(), file!());
-    assert_eq!(loc.line(), 16);
+    assert_eq!(loc.line(), 14);
     assert_eq!(loc.column(), 15);
 
     // `Location::caller()` in a macro should behave similarly to `file!` and `line!`,
     // i.e. point to where the macro was invoked, instead of the macro itself.
     let loc2 = caller_location_from_macro!();
     assert_eq!(loc2.file(), file!());
-    assert_eq!(loc2.line(), 23);
+    assert_eq!(loc2.line(), 21);
     assert_eq!(loc2.column(), 16);
 }
diff --git a/src/test/ui/rfc-2091-track-caller/const-caller-location.rs b/src/test/ui/rfc-2091-track-caller/const-caller-location.rs
index 0614c52c66036..8030a4d967a67 100644
--- a/src/test/ui/rfc-2091-track-caller/const-caller-location.rs
+++ b/src/test/ui/rfc-2091-track-caller/const-caller-location.rs
@@ -1,6 +1,6 @@
 // run-pass
 
-#![feature(const_fn, track_caller)]
+#![feature(const_caller_location, const_fn)]
 
 use std::panic::Location;
 
diff --git a/src/test/ui/rfc-2091-track-caller/diverging-caller-location.rs b/src/test/ui/rfc-2091-track-caller/diverging-caller-location.rs
index 1fb75ef35ffc1..6681119557d79 100644
--- a/src/test/ui/rfc-2091-track-caller/diverging-caller-location.rs
+++ b/src/test/ui/rfc-2091-track-caller/diverging-caller-location.rs
@@ -6,8 +6,6 @@
 //! we don't inspect the location returned -- it would be difficult to distinguish between the
 //! explicit panic and a failed assertion. That it compiles and runs is enough for this one.
 
-#![feature(track_caller)]
-
 #[track_caller]
 fn doesnt_return() -> ! {
     let _location = core::panic::Location::caller();
diff --git a/src/test/ui/rfc-2091-track-caller/error-odd-syntax.rs b/src/test/ui/rfc-2091-track-caller/error-odd-syntax.rs
index d6560231871c9..6f4290e2a5ee9 100644
--- a/src/test/ui/rfc-2091-track-caller/error-odd-syntax.rs
+++ b/src/test/ui/rfc-2091-track-caller/error-odd-syntax.rs
@@ -1,5 +1,3 @@
-#![feature(track_caller)]
-
 #[track_caller(1)]
 fn f() {}
 //~^^ ERROR malformed `track_caller` attribute input
diff --git a/src/test/ui/rfc-2091-track-caller/error-odd-syntax.stderr b/src/test/ui/rfc-2091-track-caller/error-odd-syntax.stderr
index 8906fa59506a7..e7ddf8df4ab53 100644
--- a/src/test/ui/rfc-2091-track-caller/error-odd-syntax.stderr
+++ b/src/test/ui/rfc-2091-track-caller/error-odd-syntax.stderr
@@ -1,5 +1,5 @@
 error: malformed `track_caller` attribute input
-  --> $DIR/error-odd-syntax.rs:3:1
+  --> $DIR/error-odd-syntax.rs:1:1
    |
 LL | #[track_caller(1)]
    | ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[track_caller]`
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs
index 1145f7786c78b..074e1ceb791ce 100644
--- a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs
+++ b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs
@@ -1,5 +1,3 @@
-#![feature(track_caller)]
-
 #[track_caller]
 extern "C" fn f() {}
 //~^^ ERROR `#[track_caller]` requires Rust ABI
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr
index e08c52fabd6b7..bcc0c8170e655 100644
--- a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr
+++ b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr
@@ -1,11 +1,11 @@
 error[E0737]: `#[track_caller]` requires Rust ABI
-  --> $DIR/error-with-invalid-abi.rs:3:1
+  --> $DIR/error-with-invalid-abi.rs:1:1
    |
 LL | #[track_caller]
    | ^^^^^^^^^^^^^^^
 
 error[E0737]: `#[track_caller]` requires Rust ABI
-  --> $DIR/error-with-invalid-abi.rs:8:5
+  --> $DIR/error-with-invalid-abi.rs:6:5
    |
 LL |     #[track_caller]
    |     ^^^^^^^^^^^^^^^
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-naked.rs b/src/test/ui/rfc-2091-track-caller/error-with-naked.rs
index f457384833335..2b110c9a32515 100644
--- a/src/test/ui/rfc-2091-track-caller/error-with-naked.rs
+++ b/src/test/ui/rfc-2091-track-caller/error-with-naked.rs
@@ -1,4 +1,4 @@
-#![feature(naked_functions, track_caller)]
+#![feature(naked_functions)]
 
 #[track_caller] //~ ERROR cannot use `#[track_caller]` with `#[naked]`
 #[naked]
diff --git a/src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs b/src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs
index 76e62b89ab818..74217f47084a3 100644
--- a/src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs
+++ b/src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs
@@ -1,7 +1,5 @@
 // run-pass
 
-#![feature(track_caller)]
-
 macro_rules! caller_location_from_macro {
     () => (core::panic::Location::caller());
 }
@@ -9,13 +7,13 @@ macro_rules! caller_location_from_macro {
 fn main() {
     let loc = core::panic::Location::caller();
     assert_eq!(loc.file(), file!());
-    assert_eq!(loc.line(), 10);
+    assert_eq!(loc.line(), 8);
     assert_eq!(loc.column(), 15);
 
     // `Location::caller()` in a macro should behave similarly to `file!` and `line!`,
     // i.e. point to where the macro was invoked, instead of the macro itself.
     let loc2 = caller_location_from_macro!();
     assert_eq!(loc2.file(), file!());
-    assert_eq!(loc2.line(), 17);
+    assert_eq!(loc2.line(), 15);
     assert_eq!(loc2.column(), 16);
 }
diff --git a/src/test/ui/rfc-2091-track-caller/only-for-fns.rs b/src/test/ui/rfc-2091-track-caller/only-for-fns.rs
index 0fd59b4bf4918..bc0ca9552806f 100644
--- a/src/test/ui/rfc-2091-track-caller/only-for-fns.rs
+++ b/src/test/ui/rfc-2091-track-caller/only-for-fns.rs
@@ -1,5 +1,3 @@
-#![feature(track_caller)]
-
 #[track_caller]
 struct S;
 //~^^ ERROR attribute should be applied to function
diff --git a/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr b/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr
index c2fb8fa1eb6ca..6666dcfa6e599 100644
--- a/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr
+++ b/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr
@@ -1,5 +1,5 @@
 error[E0739]: attribute should be applied to function
-  --> $DIR/only-for-fns.rs:3:1
+  --> $DIR/only-for-fns.rs:1:1
    |
 LL | #[track_caller]
    | ^^^^^^^^^^^^^^^
diff --git a/src/test/ui/rfc-2091-track-caller/pass.rs b/src/test/ui/rfc-2091-track-caller/pass.rs
index eef83b3d68f97..ada150b25cf2c 100644
--- a/src/test/ui/rfc-2091-track-caller/pass.rs
+++ b/src/test/ui/rfc-2091-track-caller/pass.rs
@@ -1,6 +1,4 @@
 // run-pass
-#![feature(track_caller)]
-
 #[track_caller]
 fn f() {}
 
diff --git a/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs b/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs
index 76a380ed3e30d..efcc1f6942de1 100644
--- a/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs
+++ b/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs
@@ -1,7 +1,5 @@
 // run-pass
 
-#![feature(track_caller)]
-
 use std::panic::Location;
 
 #[track_caller]
@@ -20,21 +18,21 @@ fn nested_tracked() -> &'static Location<'static> {
 fn main() {
     let location = Location::caller();
     assert_eq!(location.file(), file!());
-    assert_eq!(location.line(), 21);
+    assert_eq!(location.line(), 19);
     assert_eq!(location.column(), 20);
 
     let tracked = tracked();
     assert_eq!(tracked.file(), file!());
-    assert_eq!(tracked.line(), 26);
+    assert_eq!(tracked.line(), 24);
     assert_eq!(tracked.column(), 19);
 
     let nested = nested_intrinsic();
     assert_eq!(nested.file(), file!());
-    assert_eq!(nested.line(), 13);
+    assert_eq!(nested.line(), 11);
     assert_eq!(nested.column(), 5);
 
     let contained = nested_tracked();
     assert_eq!(contained.file(), file!());
-    assert_eq!(contained.line(), 17);
+    assert_eq!(contained.line(), 15);
     assert_eq!(contained.column(), 5);
 }
diff --git a/src/test/ui/rfc-2091-track-caller/track-caller-ffi.rs b/src/test/ui/rfc-2091-track-caller/track-caller-ffi.rs
index 23c17d743c43c..5115f687c2632 100644
--- a/src/test/ui/rfc-2091-track-caller/track-caller-ffi.rs
+++ b/src/test/ui/rfc-2091-track-caller/track-caller-ffi.rs
@@ -1,7 +1,5 @@
 // run-pass
 
-#![feature(track_caller)]
-
 use std::panic::Location;
 
 extern "Rust" {
@@ -30,21 +28,21 @@ mod provides {
 fn main() {
     let location = Location::caller();
     assert_eq!(location.file(), file!());
-    assert_eq!(location.line(), 31);
+    assert_eq!(location.line(), 29);
     assert_eq!(location.column(), 20);
 
     let tracked = unsafe { rust_track_caller_ffi_test_tracked() };
     assert_eq!(tracked.file(), file!());
-    assert_eq!(tracked.line(), 36);
+    assert_eq!(tracked.line(), 34);
     assert_eq!(tracked.column(), 28);
 
     let untracked = unsafe { rust_track_caller_ffi_test_untracked() };
     assert_eq!(untracked.file(), file!());
-    assert_eq!(untracked.line(), 26);
+    assert_eq!(untracked.line(), 24);
     assert_eq!(untracked.column(), 9);
 
     let contained = rust_track_caller_ffi_test_nested_tracked();
     assert_eq!(contained.file(), file!());
-    assert_eq!(contained.line(), 14);
+    assert_eq!(contained.line(), 12);
     assert_eq!(contained.column(), 14);
 }
diff --git a/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs b/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs
index b17c1efb3d38c..5fcfea96d547a 100644
--- a/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs
+++ b/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs
@@ -1,7 +1,5 @@
 // run-pass
 
-#![feature(track_caller)]
-
 fn pass_to_ptr_call<T>(f: fn(T), x: T) {
     f(x);
 }
diff --git a/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs b/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs
index 8ee4d4fa16871..4415d850c241c 100644
--- a/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs
+++ b/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs
@@ -1,7 +1,5 @@
 // run-pass
 
-#![feature(track_caller)]
-
 fn ptr_call(f: fn()) {
     f();
 }
diff --git a/src/test/ui/rfc-2091-track-caller/tracked-trait-impls.rs b/src/test/ui/rfc-2091-track-caller/tracked-trait-impls.rs
index 0a5f92bb635e5..4db4c29e53d58 100644
--- a/src/test/ui/rfc-2091-track-caller/tracked-trait-impls.rs
+++ b/src/test/ui/rfc-2091-track-caller/tracked-trait-impls.rs
@@ -1,7 +1,5 @@
 // run-pass
 
-#![feature(track_caller)]
-
 macro_rules! assert_expansion_site_is_tracked {
     () => {{
         let location = std::panic::Location::caller();
diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr b/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr
index 1e51567a9b1c4..5516d4a4c1c1c 100644
--- a/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr
+++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr
@@ -9,7 +9,7 @@ help: if this is a `self` type, give it a parameter name
    |
 LL | trait Trait2015 { fn foo(#[allow(C)] self: i32); }
    |                                      ^^^^^^^^^
-help: if this was a parameter name, give it a type
+help: if this is a parameter name, give it a type
    |
 LL | trait Trait2015 { fn foo(#[allow(C)] i32: TypeName); }
    |                                      ^^^^^^^^^^^^^
diff --git a/src/test/ui/span/issue-34264.stderr b/src/test/ui/span/issue-34264.stderr
index 116f5ddd5b4b2..40c3219bf27b0 100644
--- a/src/test/ui/span/issue-34264.stderr
+++ b/src/test/ui/span/issue-34264.stderr
@@ -21,7 +21,7 @@ LL | fn foo(Option<i32>, String) {}
    |                           ^ expected one of `:`, `@`, or `|`
    |
    = note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
-help: if this was a parameter name, give it a type
+help: if this is a parameter name, give it a type
    |
 LL | fn foo(Option<i32>, String: TypeName) {}
    |                     ^^^^^^^^^^^^^^^^
@@ -41,7 +41,7 @@ help: if this is a `self` type, give it a parameter name
    |
 LL | fn bar(self: x, y: usize) {}
    |        ^^^^^^^
-help: if this was a parameter name, give it a type
+help: if this is a parameter name, give it a type
    |
 LL | fn bar(x: TypeName, y: usize) {}
    |        ^^^^^^^^^^^